So I'm trying to fetch data from my API and I'm able to log it into console, but I can't render it into my app using useState. Tried something like that and it completely ignores my h2.
var id = "61bf209bdb079818ec63d9fd";
const Main = () => {
const [name, setName] = useState("");
const [fromApi, setFromApi] = useState([]);
const getApiData = () => {
fetch('http://localhost:3000/myapi')
.then(res => {
return res.json();
})
.then(data => {
console.log(data);
setFromApi(data);
})
for (var i = 0; i < fromApi.length; i ) {
if (fromApi[i]._id === id) {
setName(fromApi[i].name);
}
}
}
useEffect(() => {
getApiData();
}, [])
return (
<div>
{name && <h2 className='urname'>Your name: {name}</h2>}
</div>
)
}
CodePudding user response:
This is happening because React does not guarantee that the state changes are applied immediately. This makes reading state right after updating (in your case setFromApi) a potential pitfall and can potentially return the existing value due to async nature.
- Calling
setState
only affects the next render and does not change state in the already running code
React Doc: https://reactjs.org/docs/react-component.html?#setstate
In your case you're using data receiving from API and running for
loop even before fromAPI
state gets updated. Instead put fromAPI
in dependency array to useEffect
and perform your for
loop there.
var id = "61bf209bdb079818ec63d9fd";
const Main = () => {
const [name, setName] = useState("");
const [fromApi, setFromApi] = useState([]);
const getApiData = () => {
fetch('http://localhost:3000/myapi')
.then(res => {
return res.json();
})
.then(data => {
console.log(data);
setFromApi(data);
})
}
useEffect(() => {
getApiData();
}, [])
useEffect(() => {
if(fromApi?.length){
for (var i = 0; i < fromApi.length; i ) {
if (fromApi[i]._id === id) {
setName(fromApi[i].name);
}
}
}
}, [fromApi])
return (
<div>
{name && <h2 className='urname'>Your name: {name}</h2>}
</div>
)
}
CodePudding user response:
I would consider why you have two states of fromApi
and name
? You could just setName
as soon as the data comes back from the API...something like:
const [name, setName] = useState("");
const getApiData = () => {
fetch('http://localhost:3000/myapi')
.then(res => {
return res.json();
})
.then(data => {
console.log(data);
for (var i = 0; i < data.length; i ) {
if (data[i]._id === id) {
setName(data[i].name);
// Stop the for loop once match has been found
return;
}
}
})
}