Reputation: 85
I was wondering if you could comment on best practices in the scenario below: I have a react page and am using an async call to get some data. On the page, I render some of that data that is returned like so. (setTimeout is in there so i can see it load - also API is public so you can see what it returns)
App.js
function App() {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
fetch("https://swapi.dev/api/people/1").then((response) =>
response.json().then((data) => {
setData(data);
setIsLoading(false);
console.log(data);
})
);
}, 2000);
}, []);
return (
<React.Fragment>
<p>{data.name}</p> //will be blank until aysnc call completes. THIS IS FINE.
<p>{data.films[0]}</p> //throws an error - trying to access an index that doesn't exist. PROBLEM
</React.Fragment>
);
}
I found a way around this, but I litter my code EVERYWHERE with the following. Plus I have to do it again in child components that i pass this data to.
<p>{isLoading ? "loading..." : data.films[0]}</p>
Does anyone know a better way or best practice for this?
Upvotes: 0
Views: 28
Reputation: 64695
I mean in this case specifically it might make sense to just set the initial state to something sensible:
const [data, setData] = useState({
name: '',
films: []
});
Otherwise, just don't render at all until you have data:
Upvotes: 0
Reputation: 4097
Don't use two state variables, just use one, and check if it's been set yet.
const [data, setData] = useState();
<p>{!data ? "loading..." : data.films[0]}</p>
Plus I have to do it again in child components that i pass this data to.
Maybe only call the child components once the data is loaded?
<div>{data && <SomeChild data={data} />}</div>
Remember that you can use optional chaining too, it can help in these situations
<p>{data?.films[0]}</p>
Upvotes: 1