-2

I use hook useState for set post value.

const [firstPost, setFirstPost] = useState();

useEffect(() => {
  (async () => { await onFetchPosts(); })();
}, []);

const onFetchPosts = async () => {
    try {
       const { body } = await publicService.fetchPostById(119);

       // get post
       const post = body.posts;
       if (post && post.postsId) {
         console.log(`save...`, body.posts);
         setFirstPost(body.posts);
       }

       console.log(`firstPost...`, firstPost);

     } catch (error) {
         console.log(error);
     } finally {
            setLoading(false);
   }
}

enter image description here

I dont understand, firstPost is not updated.

Anh NC
  • 47
  • 10
  • Setting the state is a thing that react schedules. It may not be available right in the next line. – Nikki9696 Jul 14 '21 at 17:08
  • Here is a link explaining it better than I can - https://dmitripavlutin.com/how-react-updates-state/ – Nikki9696 Jul 14 '21 at 17:11
  • thanks, i try read it. – Anh NC Jul 14 '21 at 17:12
  • Does this answer your question? [Why calling setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/42593202/why-calling-setstate-method-doesnt-mutate-the-state-immediately) – pilchard Jul 14 '21 at 17:17

2 Answers2

0

This is because setState calls are asynchronous. Read it here and here. As the per the doc I linked

  • setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state
  • setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall

Therefore, the state is usually not updated yet when you console.log it on the next line, but you can access/see the updated state on the next render. If you want to log values, you can put them as inside a <pre> tag in your HTML, or do console.log at the beginning, like below:

const [firstPost, setFirstPost] = useState();

// Console.log right on at the start of the render cycle
console.log("First post", firstPost);

useEffect(() => {
  (async () => {
    await onFetchPosts();
  })();
}, []);

const onFetchPosts = async () => {
  try {
    const { body } = await publicService.fetchPostById(119);

    // get post
    const post = body.posts;
    if (post && post.postsId) {
      console.log(`save...`, body.posts);
      setFirstPost(body.posts);
    }
    // Do not console.log the state here
    // console.log(`firstPost...`, firstPost);
  } catch (error) {
    console.log(error);
  } finally {
    setLoading(false);
  }
};

// Can also debug like this
return <pre>{JSON.stringify(firstPost)}</pre>;
Bao Huynh Lam
  • 974
  • 4
  • 12
  • i want to use firstPost in orther func, not in template ` const listenToScroll = (event) => { if (!isLogined) { return; }; if (!firstPost || firstPost.read === true) { return; }; const relativePost = document.querySelector('.relative-posts'); if (relativePost) { const { offsetTop } = relativePost; if (offsetTop - window.scrollY <= 740) { onReadPost(); } } } ` – Anh NC Jul 14 '21 at 17:28
  • but firstPost in this func is null. – Anh NC Jul 14 '21 at 17:28
  • That seems like an extra problem of how you design the other functions. If you make and edit to the question that includes this other function that is using `firstPost`, I may be able to debug better. – Bao Huynh Lam Jul 14 '21 at 18:01
0

React may batch multiple setState() calls into a single update for performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

React does not change the state variables immediately when state is changed i.e why you are getting undefined in console.

However the new value of firstPost is assured to be there in the next render.