I have been struggling myself silly to get data read from a local json file and fed into a React render function. I first read the code in via a class through the componentDidMount
method, but the data always arrived later than the render function executed. I have looked at a number of solutions. Most people seem to recommend the use of useEffect
and useState
to get around this issue.
This is what I have so far:
import React, {useEffect, useState} from 'react';
import axios from "axios";
export default function Foo() {
const [list, setProjects] = useState(null)
useEffect(() => {
axios.get('data.json')
.then(response => {
setProjects(response.data)
})
}, [])
console.log(list);
debugger;
if (list !== null) {
return (
<div>
Project: {/*{list.projects[0].title}*/}
</div>
)
} else {
return (
<div>
Loading Project Data ...
</div>
)
}
}
The incoming data comes in the format {"projects": [{"id": 1, "title": "some title", ...}, ... {...}]}
.
Issue is, even though I have a null check wrapping around the return, the code always jumps into the first branch, and complains that there is nothing (nothing is shown with Project: {list}
and Project: {list.projects[0].title}
errors because list is deemed to be null). The console shows the data loading, but I suspect there is an async issue at play related to the promise. I have tuned the initial state, but no luck so far.
EDIT:
Thank you to all the replies received. Whilst they helped to streamline the code and added extra checks, I still had the same issue with the data not being displayed. It seems the problem lay with the initial value I assigned. I changed these to:
const [list, setProjects] = useState({projects: [{title: "XXX"}]});
And the code worked fine. I guess this dummy value gets overwritten by the actual json vales once these became available.
try create another state
const [loading, setLoading] = useState(true); useEffect(() => { setLoading(true); axios.get('data.json').then(response => { setProjects(response.data); setLoading(false); }) }, []) if (loading) { else{ }
Try using another variable isLoading, when the axios works to fetch the data set it to true and the after the response set it to False. Try the following code:
import React, {useEffect, useState} from 'react';
import axios from "axios";
export default function Foo() {
const [list, setProjects] = useState(null);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
setIsLoading(true);
axios.get('data.json')
.then(response => {
setProjects(response.data);
setIsLoading(false);
})
}, []);
console.log(list);
debugger;
return (
<React.Fragment>
{isLoading && <h1>Loading Data.........</h1>}
{!isLoading && (<div> Project: {/*{list.projects[0].title}*/}</div>)}
</React.Fragment>
);
}
Instead of this:
if (list !== null) {
return (
<div>
Project: {/*{list.projects[0].title}*/}
</div>
)
} else {
return (
<div>
Loading Project Data ...
</div>
)
}
I would do something like this:
return (
<div>
{list && list.projects && list.projects.length > 0 ? (
<p>{list.projects[0].title}</p>
) : (
<p>Loading Project Data...</p>
)}
</div>
);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.