0

I think this question has kind of been answered before, but I've tried looking through all the similar-titled questions and I'm still a bit confused.

My code requests some data from the what3words API, and then the data is given a variable within an object using setState. However, it is out of sync, so the console.log(modifiedData) shows slug as an empty string. But when you click the submit button again, slug has been updated.

const api = require("@what3words/api");
const [modifiedData, setModifiedData] = useState({
    title: '',
    description: '',
    category: '',
    condition: '',
    capacity: 0,
    slug: '',
    lng: 0,
    lat: 0,
  });
  
const handleSubmit = async e => {
   e.preventDefault();
   api.convertTo3wa({lat: modifiedData.lat, lng: modifiedData.lng}, 'en')
   .then(function(getSlug) {
      setModifiedData((prev) => ({
        ...prev,
        slug: getSlug.words,
      }));
      console.log(modifiedData);
    });
edapm
  • 35
  • 1
  • 9

3 Answers3

1

This is because setState has asynchronous behaviour, so you can't guarantee the data has been updated when you make the console.log.

You have to wait for the component to reRender to ensure your data is there.

const [state, setState = useState(..)
const submitHandler = (e) =>{

setState({... some data})

console.log(state) //data is not gaurenteed
}

console.log(state) // first time : {} 
                   //second time is the data
return(
<div>
<p>app content </p>
</div>
)
}
Dedi
  • 2,812
  • 3
  • 22
  • 55
  • how do I ensure the data is up-to-date before I console.log it? – edapm Mar 10 '21 at 20:52
  • @edapm this is guaranteed to be possible in the same function. You have to wait for the component to reRender. – Dedi Mar 10 '21 at 20:53
  • @edapm Here is the only way to ensure the state variable is updated before you console.log it `useEffect(() => console.log(modifiedData), [modifiedData])` – codemonkey Mar 10 '21 at 20:59
  • @codemonkey How do I do this within an event handler? – edapm Mar 10 '21 at 21:03
  • 1
    @edapm Do what exactly? Your question doesn't mention anything about event handlers. You should ask a separate question regarding it. – codemonkey Mar 10 '21 at 21:09
1

Much like setState in Class components created by extending React.Component or React.PureComponent, the state update using the updater provided by useState hook is also asynchronous, and will not be reflected immediately.

Look at this satck overflow question

BeK
  • 161
  • 1
  • 6
0

It's like Ating said. If you want to see the change with console.log you can wrap it with setTimeOut:

const api = require("@what3words/api");
const [modifiedData, setModifiedData] = useState({
   title: '',
   description: '',
category: '',
condition: '',
capacity: 0,
slug: '',
lng: 0,
lat: 0,
  });
const handleSubmit = async e => {
  e.preventDefault();
  api.convertTo3wa({lat: modifiedData.lat, lng: 
  modifiedData.lng}, 'en')
  .then(function(getSlug) {
  setModifiedData((prev) => ({
    ...prev,
    slug: getSlug.words,
  }));
  setTimeOut(()=>{
   console.log(modifiedData);
  },500)      
});
JsThiago
  • 61
  • 1
  • 7