bmccormick
bmccormick

Reputation: 85

React - setting state of an async response

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

Answers (2)

dave
dave

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

Snow
Snow

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

Related Questions