0

I am new to React and I have this simple code and I got two questions:

import { useState, useEffect } from 'react';

const UpdateArticle = () => {
  let filteredArticle;
  const id = 2;
  const [theArticle, setTheArticle] = useState({});

  const testArticles = [
    {
      id: 1,
      title: 'Maxaan qabtaa?',
      body: 'Wax daran bay ku hadlayaan kuwa halkaan ila jooga.',
      writer: 'Jama',
    },
    {
      id: 2,
      title: 'Why django?',
      body: 'Simple: it is very simple.',
      writer: 'Dennis',
    },
  ];

  const updateArticle = () => {
    filteredArticle = testArticles.find((article) => article.id === id);
    setTheArticle(filteredArticle);
  };
  // console.log("Test");
  useEffect(() => {
    updateArticle();
    console.log('Test');
    console.log(filteredArticle);
    console.log(theArticle);
  }, [id]);

  return (
    <div className="article update">
      <h1>{theArticle.title}</h1>
    </div>
  );
};
  1. Why is the setTheArticle method is not setting the theArticle instantly? The console.log in the useEffect gives an empty object even though the filteredArticle above it has a correct value.

  2. the console does everything twice. This is the case even if I put one outside useEffect and outside the updateArticle function. for example, for the above case it gives something like this:

Test {id: 2, title: "Why django?", body: "Simple: it is very simple.", writer: "Dennis"} {} (empty???) Test {id: 2, title: "Why django?", body: "Simple: it is very simple.", writer: "Dennis"} {} (empty???)

The question is why?

I even suspected it is my configuration and went to stackblitz. The same thing. and also I am NOT calling the component twice.

Daniel Steinmann
  • 2,119
  • 2
  • 15
  • 25
Hashi
  • 1
  • 2
  • `useEffect` fires twice in the development mode with StrictMode: https://react.dev/reference/react/useEffect#my-effect-runs-twice-when-the-component-mounts. For the first question refer to this post: [The Most Common Mistakes When Using React](https://claritydev.net/blog/the-most-common-mistakes-when-using-react). – Clarity Apr 15 '23 at 11:26
  • Sounds like your code is wrapped with [StrictMode](https://stackoverflow.com/questions/53183362/what-is-strictmode-in-react). – Andy Apr 15 '23 at 11:26
  • 1
    1) [The useState set method is not reflecting a change immediately](https://stackoverflow.com/questions/54069253/the-usestate-set-method-is-not-reflecting-a-change-immediately) 2) [Why is my React component is rendering twice?](https://stackoverflow.com/questions/48846289/why-is-my-react-component-is-rendering-twice) – Guy Incognito Apr 15 '23 at 11:28
  • Even if I remove the useState and the useEffect, still the component fires twice and prints everything twice @Clarity – Hashi Apr 15 '23 at 11:40
  • Yes that is true @Andy. Is this problematic? Edit: Yep it is the cause of the double rendering. thanks. – Hashi Apr 15 '23 at 11:42
  • No. mseyfayi's answer below has a link to the documentation so you can read up on it if you want. @Hashi – Andy Apr 15 '23 at 11:45
  • how *could* calling `setTheArticle` immediately change the value of `theArticle` on the next line of code? `theArticle` is a const! What it instead does is make React rerender your component (call the whole function again), and that time, the `useState` call will give you back the updated value as the `theArticle` for that render. – Robin Zigmond Apr 15 '23 at 11:58

2 Answers2

3

Answers to your questions:

  1. setState will not fire immediately and if you want to get the new state you should listen to it in another useEffect with this state as its dependency.
  2. Firing the useEffect twice is because of the StrictMode. You can read about that in the React docs.

Some advice base on your example code:

  1. Try to use callback in setState for changing the previous state:
const updateArticle = () => {
    setTheArticle(prev => prev.find((article) => article.id === id));
  };
  1. Put all used data in a useEffect in its dependencies array.
  2. Read docs of the react.dev carefully to avoid unexpected behavior.
Andy
  • 61,948
  • 13
  • 68
  • 95
mseyfayi
  • 116
  • 5
0

useState is an asynchronous hook and it doesn't change the state immediately, it has to wait for the component to re-render. useRef is a synchronous hook that updates the state immediately and persists its value through the component's lifecycle, but it doesn't trigger a re-render.

To use callback in the useState hook, we need to use the useEffect hook that triggers after state update and call the function after that. We need to pass state in the useEffect Dependency Array. useEffect is triggered when the state updates and then calls the inside function immediately.

you can log the state inside JSX to see actual value of the state when component has been mounted (componentDidMount)

read the following link javascript plainenglish, useState

vFlag
  • 1
  • 2