1

When updating state when props change, the commonly held approach is to use useEffect() with the prop as a dependency:

const Component = ({prop}) => {
  const [state, setState] = useState(prop);

  useEffect(() => {
    setState(prop);
  }, [prop]);

  return <div>{state}</div>;
}

I have to wonder, is there an advantage to this over doing a comparison directly in the component itself, like so:

const Component = ({prop}) => {
  const [state, setState] = useState(prop);

  if (prop !== state) {
    setState(prop);
  }

  return <div>{state}</div>;
}

It looks like both approaches cause the component to execute twice -- once with the prop and state out of sync, once in sync -- but the second approach looks like it avoids adding a hook to the stack. It also looks like it could be optimized out of the DOM reconciliation, since it doesn't have to wait for the DOM to be generated the way useEffect() does. I'm not even sure it is easier to read, other than being "The Hooks Way."

Does anyone have an idea why the useEffect() route could be better than the inline check?

Michael Landis
  • 1,074
  • 7
  • 12

2 Answers2

3

The official React docs use the second approach for syncing props to state:

https://reactjs.org/docs/hooks-faq.html#how-do-i-implement-getderivedstatefromprops

function ScrollView({row}) {
  const [isScrollingDown, setIsScrollingDown] = useState(false);
  const [prevRow, setPrevRow] = useState(null);

  if (row !== prevRow) {
    // Row changed since last render. Update isScrollingDown.
    setIsScrollingDown(prevRow !== null && row > prevRow);
    setPrevRow(row);
  }

  return `Scrolling down: ${isScrollingDown}`;
}

The difference between updating state in useEffect and updating state during render is that, useEffect is called after React already commits the updates, i.e. the updates would be reflected in DOM, then you'll update state which will update the DOM again. The second way causes a re-render, but there's only one commit to the DOM.

satya164
  • 9,464
  • 2
  • 31
  • 42
0

I think it's important to understand when to use hooks and when not too. The answer to this question is a very helpful How does React implement hooks so that they rely on call order.

We have recently discovered a lot of problems to do with the useEffect hook, one of them being

useEffect(() => {
  // Called on first render and every props.foo update
}, [props.foo])

We didn't want it to be called on the first render only on every update.

Another on being useEffect gives warning when using objects & arrays, instead of a value. I'm not saying don't use the useEffect ever I love the useEffect hook, but instead of saying why shouldn't use it. You should say do I need useEffect to get what I need to achieve.

For your example unless you are setting the state at another point I would suggest. Just using the prop. If you are setting the state I would have a look at the above link at the schema found.

The schema of a single hook is as below. It can be found in the implementation

function createHook(): Hook {
  return {
    memoizedState: null,

    baseState: null,
    queue: null,
    baseUpdate: null,

    next: null,
  };
}

Think do I need to make use of the hooks queue when setting the state, if not then don't use a hook.

Another good use of the hook is are you going to be putting multiple values in the hook array if so it's a good idea to use it then!

Hope that helps :)

Alex Dunlop
  • 1,383
  • 15
  • 24
  • I think I made my example too terse by considering the prop object versus a property. I meant a specific property named 'prop'. I'll update the code to reflect that. – Michael Landis Mar 11 '20 at 23:19