Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React useEffect and return render

I have a useEffect with fetch and I would like to render it first, since it runs the else case first and then runs the useEffect. Which shows the else case then the posts when viewing the page. Is there a way to render useEffect first?

const [posts, setPosts] = useState([]);

useEffect(() => {
  const data = await fetch('https://localhost:1111/api/posts', {
    credentials: 'include'
  });
  const response = await data.json();
  setPosts(response);
}, []);

return (
  <div>
    {posts.length > 0 ? (
      posts.map(post => (
        <Post key={post.id} onUpdate={() => handleUpdate()} post={post} />
      ))
    ) : (
      <p>No posts</p>
    )}
  </div>
);
like image 690
deinnielle Avatar asked Apr 23 '26 14:04

deinnielle


1 Answers

You can get that result, but you'll need to do it a different way.

When your component renders for the first time, the entire function will run, and then the page will be updated based on what your function returned. This happens more or less synchronously. Only after it has rendered will your effects run. It's not possible to change the order of this: render is always first, effects are always after the render.

So if you don't want anything to display until that effect can complete, you need to return a null from the render. Then when the fetch is complete, you update state, which causes it to render again, this time not with a null.

For example, here i've taken your code and added one more possibility: the state might be null. I'm using this to indicate that it hasn't loaded yet. Later, once the data has been fetched, the state gets updated and the component rerenders.

const [posts, setPosts] = useState(null);

useEffect(() => {
  (async () => {
    const data = await fetch('https://localhost:1111/api/posts', {
      credentials: 'include'
    });
    const response = await data.json();
    setPosts(response);
  })();
}, []);

if (posts === null) {
  return null;
}

return (
  <div>
    {posts.length > 0 ? (
      posts.map(post => (
        <Post key={post.id} onUpdate={() => handleUpdate()} post={post} />
      ))
    ) : (
      <p>No posts</p>
    )}
  </div>
);
like image 108
Nicholas Tower Avatar answered Apr 26 '26 06:04

Nicholas Tower