0

I want to have "ans" logged in console as soon as I click on the submit button. But the problem is I have to press the submit button twice to see the log. The states like iValue, pValue, nValue, etc. are updated the first time button is clicked though.I came to know that I shouldn't write parseFloat(e.target.value) in onChange event handler. However, the problem still persists. Here is the code snippet. For the record, the formula I am trying to implement is ans = pValue * (iValue + 1)^nValue

import React, {useState} from 'react';
import {Link} from 'react-router-dom';
import { Col, Button, Form, FormGroup, Label, Input } from 'reactstrap';

export default function FirstComponent() {
    const [pvalue, setPvalue] = useState(0);
    const [ivalue, setIvalue] = useState(0);
    const [nvalue, setNvalue] = useState(0);
    const [ans, setAns] = useState(null);

    const submitHandler = (e) => {
        e.preventDefault();
        let temp = ivalue + 1;
        temp = ((temp ** nvalue)*pvalue).toFixed(2)
        setAns(temp)
        console.log(ans)
    }

    return (
      <Form className="container" onSubmit={submitHandler}>
        <FormGroup row>
          <Label for="form1" sm={2}>
            P value
          </Label>
          <Col sm={10}>
            <Input
              type="text"
              name="pvalue"
              id="form1"
              placeholder="Enter the value of P"
              onChange={(e) => setPvalue(parseFloat(e.target.value))}
            />
          </Col>
        </FormGroup>
        <FormGroup row>
          <Label for="form2" sm={2}>
            I value
          </Label>
          <Col sm={10}>
            <Input
              type="text"
              name="ivalue"
              id="form2"
              placeholder="Enter the value of I"
              onChange={(e) => setIvalue(parseFloat(e.target.value))}
            />
          </Col>
        </FormGroup>
        <FormGroup row>
          <Label for="form3" sm={2}>
            N value
          </Label>
          <Col sm={10}>
            <Input
              type="text"
              name="nvalue"
              id="form3"
              placeholder="Enter the value of N"
              onChange={(e) => setNvalue(parseFloat(e.target.value))}
            />
          </Col>
        </FormGroup>
        <FormGroup check row>
          <Col sm={{ size: 10, offset: 2 }}>
            <Button>Submit</Button>
          </Col>
        </FormGroup>
        <p style={{ alignItems: "center" }}>
          <Link to="/">Go back</Link>
        </p>
      </Form>
    );
}
Suraj Oberai
  • 304
  • 5
  • 14
  • Sounds like stale state to me. Maybe you need to use `useCallback`? – evolutionxbox Sep 07 '20 at 13:04
  • Setting state is async which means you will not be able to log it right after you change it. You should use useCallback – Lazar Nikolic Sep 07 '20 at 13:07
  • Does this answer your question? [React form onChange->setState one step behind](https://stackoverflow.com/questions/28773839/react-form-onchange-setstate-one-step-behind) – DBS Sep 07 '20 at 13:13

3 Answers3

4

State Updates May Be Asynchronous. It is mentioned clearly in the React docs: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous That's why ans is still old value when you tried to log if right after calling setAns(). If you want to log whenever ans is updated, can useEffect

const logChange = useEffect(() => {
    console.log('new value of ans ', ans);
  }, [ans]);
Nhut Dinh Ba
  • 354
  • 1
  • 6
1

Setting state is async which means you will not be able to log it right after you change it. You should use useCallback

 const logChange = useCallback(item => {
    console.log('new value of ans ', ans);
  }, [ans]);

    const submitHandler = (e) => {
        e.preventDefault();
        let temp = ivalue + 1;
        temp = ((temp ** nvalue)*pvalue).toFixed(2)
        setAns(temp)
        logChange()
    }
Lazar Nikolic
  • 4,261
  • 1
  • 22
  • 46
1

Try to use react hook useEffect to log updated state of 'ans'

useEffect(() => {
    console.log(ans);
});

Have a look at the docs: https://reactjs.org/docs/hooks-effect.html

ASG
  • 513
  • 3
  • 10