Reputation: 7
I am using Functional components and am a beginner.I am receiving the response from API successfully but when I am setting it to the local useState variable, it still remains empty.I am unable to understand how to fix this.
Approach 1:
const [sites,setSites]=useState([]);
useEffect(()=>{
getAllSites().then(res=>{
console.log("res",res.sites);//response received successfully
setSites(res.sites);
console.log(sites);//return empty array
})
.catch(err=>{
console.log("Error:",err);
})
},[])
Approach 2:
const [sites,setSites]=useState([]);
useEffect(()=>{
getAllSites().then(res=>{
console.log("res",res.sites);
},(res)=>{
setSites(res);//thought maybe because of async nature, so tried using callback but still empty
})
.catch(err=>{
console.log("Error:",err);
})
},[])
Can someone help me out with this?
Upvotes: 0
Views: 933
Reputation: 5999
Updating state in react will not happen synchronously. That means when you call setSites
the state will not get updated then and there rather the changes or the updated state will be available in the next render.
In order to see if that is working or not, we can make use of useEffect
hook by passing the state
variable as dependency
const {useState, useEffect} = React;
const getAllSites = () => {
return new Promise(res => {
setTimeout(() => {
return res({sites:[{id:1, name:"Google"}, {id:2, name:"Facebook"}]});
}, 500)
})
}
const App = () => {
const [sites,setSites] = useState([]);
useEffect(()=>{
getAllSites().then(res=>{
//console.log("res",res.sites);//response received successfully
setSites(res.sites);
})
.catch(err=>{
console.log("Error:",err);
})
},[]);
useEffect(() => {
//This will print on mount as well as when there's any change in `sites`
console.log(sites);
}, [sites])
return <p>App</p>
}
ReactDOM.render(<App />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="react"></div>
And, while the data is being fetched you can display the loading indication and once the data is available you can hide loading and display the actual data.
Upvotes: 1
Reputation: 1004
You are doing everything correct. But you cannot see immediately updated value in the sites (obviously it is const) so you will see on the next render cycle, when your functional component will be run and react will assign new value to the sites. Once state updated new rerendering will happen. Just add console.log(sites)
to the top level of your functional component
const [sites,setSites]=useState([]);
console.log(sites);
useEffect(()=>{...},[]);
Upvotes: 0