zombie babe
zombie babe

Reputation: 33

React State Hook - I can't set state

I am trying to implement Facebook login to my React app.

const [formData, setFormData] = useState({
    name: "",
    surname: "",
    email: "",
    password: "",
  });

Facebook login here

<FacebookLogin
 appId=""
 autoLoad={true}
 fields="first_name,last_name,email,id"
 onClick={(e) => componentClicked(e)}
 callback={(response) => responseFacebook(response)}
 textButton={msg}
 cssClass="btn btn-primary btn-sm"
 icon="fa-facebook"
 />

The data is coming to:

const responseFacebook = (response) => {
    setFormData({ ...formData, name: response.first_name });
    setFormData({ ...formData, surname: response.last_name });
    setFormData({ ...formData, email: response.email });
    setFormData({ ...formData, password: response.id });
    console.log(formData.name);
    console.log(formData.surname);
    /* register({ name, surname, email, password }); */
  };

I can't set formData.x. response.first_name or others are working with console.log, but when I try to set the state, it turns nothing.

eg, console.log(formData.name) returns nothing.

Upvotes: 0

Views: 1014

Answers (4)

user7999267
user7999267

Reputation:

use usestate to set state and useeffect hook to console change , your state doesnt change because its an asynchronous task , in hooks there no callback function in setting state like class , so use useEffect

const responseFacebook = (response) => {
    setFormData({ 
      ...formData, 
      name: response.first_name 
      surname: response.last_name,
      email: response.email,
      password: response.id 
    });
});

useEffect(() => {
   console.log(formData.name);
    console.log(formData.surname);
}, [formData]);

Upvotes: 1

Alex Wayne
Alex Wayne

Reputation: 187252

setFormData({ ...formData, name: response.first_name });
setFormData({ ...formData, surname: response.last_name });
setFormData({ ...formData, email: response.email });
setFormData({ ...formData, password: response.id });

The problem is that formData does not change until the next render. The value of formData is the value on the previous render, and it stays that way until the next render. So each of the above lines, sets the old data, plus one changed property. Then the next lines sets the old data with a different changed property, and the property you changed before that is lost.

You just want to call setFormData once, with all the changes you want. That way you don't need formData to update at all until after you're done setting everything.

setFormData({
  ...formData,
  name: response.first_name,
  surname: response.last_name,
  email: response.email,
  password: response.id,
});

But looking at your the structure of your state here, you don't need the previous values at all since every key is in the response:

setFormData({
  name: response.first_name,
  surname: response.last_name,
  email: response.email,
  password: response.id,
});

Upvotes: 2

Ayushya
Ayushya

Reputation: 1920

useState Hooks are asynchronous, you will not be able to see the data reflected immediately, instead use useEffect to see your result

const responseFacebook = (response) => {
    setFormData({ ...formData, name: response.first_name });
    setFormData({ ...formData, surname: response.last_name });
    setFormData({ ...formData, email: response.email });
    setFormData({ ...formData, password: response.id });
    console.log(formData.name); // This won't show the results
    console.log(formData.surname); // This won't show the results
    /* register({ name, surname, email, password }); */ // This won't show the results
  };

useEffect(() => {
    // action on update of formData
 console.log(formData);
}, [formData]);

Also you could further optimise your code to:

   setFormData({ 
    ...formData,
    name: response.first_name,
    surname: response.last_name,
    email: response.email,
    password: response.id 
   });

useEffect(() => {
    // action on update of formData
 console.log(formData);
}, [formData]);

Upvotes: 0

Vencovsky
Vencovsky

Reputation: 31693

You should use the previous state or call only one time setFormData.

// using previous state
// this solves your problem but isn't that good
// because you don't need to call it many times
const responseFacebook = (response) => {
    setFormData(prev => ({ ...prev, name: response.first_name });
    setFormData(prev => ({ ...prev, surname: response.last_name });
    setFormData(prev => ({ ...prev, email: response.email });
    setFormData(prev => ({ ...prev, password: response.id });
};

OR

// calling only once
const responseFacebook = (response) => {
    setFormData({ 
         name: response.first_name,
         surname: response.last_name,
         email: response.email,
         password: response.id 
    });
};

Upvotes: 2

Related Questions