Search code examples
reactjsfetchuse-statereact-state

Child Component Sends Correct Data In Second Attempt


I am trying to send a object from my child component to its parent. I get the data through fetch, use state to update the response in a JSON object and send it via props. However, the first time I send it, it sends 'abc' or whatever value I originally assigned to the object and sends the response the second time.

function Login(props) {

  const loginAttempt = (email, password) => {
    fetch('http://localhost:5000/user/login', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        email: email,
        password: password
      })
    })
      .then(res => res.json())
      .then(data => {
        setUserData({
          status: data.status,
          name: data.name,
          token: data.token
        })
        props.handleUserData(userData)
      })
      .catch(err => console.log(err))
  }

  const classes = useStyles()

  const [email, setEmail] = React.useState('')
  const [password, setPassword] = React.useState('')
  const [userData, setUserData] = React.useState('abc')

  const handleEmail = (event) => {
    setEmail(event.target.value)
  }
  const handlePassword = (event) => {
    setPassword(event.target.value)
  }

  return (
    <div className="login-container">
      <Grid container spacing={2} direction="column" alignItems="center">
        <Grid item>
          <TextField className={classes.fieldStyle} variant="outlined" label="Email Address" onChange={handleEmail} />
        </Grid>
        <Grid item>
          <TextField className={classes.fieldStyle} variant="outlined" label="Password" type="password" onChange={handlePassword} />
        </Grid>
        <Grid item>
          <Button className={classes.buttonStyle} variant="outlined"
            onClick={() => loginAttempt(email, password)}
          >
            Login
          </Button>
        </Grid>
        <Grid item>
          <Button className={classes.buttonStyle} variant="outlined">Forgot Password</Button>
        </Grid>
      </Grid>
    </div>
  );
}

Solution

  • The setter in hooks in not synchronous, so if you do

    setUserData({
      status: data.status,
      name: data.name,
      token: data.token
    })
    

    you can not immediately access useData, because it might not be updated.

    I suggest you use useEffect that triggers when userData is updated, and update parent state from there.

    like

    useEffect(()=>{
        if(userData){
            props.handleUserData(userData)
        }
    },[userData])