Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

useState and changes in the props

I'm trying to understand what happens when you have both props and useState in one component.

I wrote little example of it which has one parent component that prints its numbers with another child component -

const MyNumbers = (props) => {
  const [numbers, setNumbers] = useState([...props.arr]);

  function changeNumbers() {
    setNumbers((nums) => [...nums.map(() => Math.floor(Math.random() * 10))]);
  }

  return (
    <div className="MyNumbers">
      <div>
        <button onClick={changeNumbers}>Chane numbers</button>
      </div>
      <div>
        {numbers.map((num, idx) => (
          <SingleNumber key={idx} num={num}></SingleNumber>
        ))}
      </div>
    </div>
  );
};
const SingleNumber = (props) => {
  const [num] = useState(props.num);
  useEffect(() => {
    console.log("useEffect called");
  });
  return <h3>The number is {num}</h3>;
};

Here is the above demo

The SingleNumber component uses useState and as you can see clicking on the "Change numbers" action doesn't change the values in the children component.

But when I wrote almost the same code but now SingleNumber doesn't use useState then clicking on the "Change numbers" changes all the values in the children component (like in this demo).

Is it correct to say that a function component with a useState renders once and then only changed if the state changed but not if the props changed ?

like image 900
URL87 Avatar asked Dec 17 '20 08:12

URL87


2 Answers

You don't need to use useState in SingleNumber.

because useState called only once when it rendered.

const SingleNumber = (props) => {
  // const [num] = useState(props.num);
  // useEffect(() => {
  //   console.log("useEffect called");
  // });
  return <h3>The number is {props.num}</h3>;
};

if you want to use useState, you can use like this.

const SingleNumber = (props) => {
   const [num, setNum] = useState(props.num);
   useEffect(() => {
     console.log("useEffect called");
     setNum(props.num);

   }, [props.num]);
  return <h3>The number is {num}</h3>;
};
like image 197
kyun Avatar answered Oct 13 '22 04:10

kyun


OFC the component "rerenders" when the props change, the useEffect hook in SingleNumber is showing you that the "render phase" is run each time the props change.... effects are run each time the component is rendered.

enter image description here

const SingleNumber = (props) => {
  const [num] = useState(props.num);
  useEffect(() => {
    console.log("useEffect called"); // <-- logged each time the component renders
  });
  return <h3>The number is {num}</h3>;
};

If you added a dependency on props.num and updated the local state (don't actually do this, it's an anti-pattern in react!), you'll see the UI again update each time the props update.

To answer your queston:

Is it correct to say that a function component with a useState renders once and then only changed if the state changed but not if the props changed?

No, this is not technically correct to say if "render" to you means strictly react rendered the component to compute a diff, react components rerender when state or props update. Yes, if "render" more generally means you visually see the UI update.

like image 21
Drew Reese Avatar answered Oct 13 '22 03:10

Drew Reese