1

I'm quite new to React and functional programming. I want to build a parent component that basically tells what the child component should render:

const Parent = (props) => {
  // blablabla...
  useEffect(() => {
    // blablabla...
    let newSomeOtherState = doSomething(stateThatFrequentlyChange, stateThatSeldomChange)
    setSomeOtherState(newSomeOtherState)
  }, [stateThatFrequentlyChange, stateThatSeldomChange])

  return <Child data={someOtherState} />
}

The problem is that I only want the parent component to listen to the stateThatSeldomChange and then update someOtherState based on the current stateThatFrequentlyChange.

If I remove stateThatFrequentlyChange, React would complain that React Hooks useEffect has missing dependencies....

How should I solve this warning?

tctco
  • 45
  • 6
  • Why aren't you passing `stateThatFrequentlyChange` directly? Aren't both the state basically the same? – NeERAJ TK Sep 19 '21 at 10:38
  • No, the code snippet is just a simple demonstration. – tctco Sep 19 '21 at 10:55
  • For anyone who is looking for the answer to similar questions, here is the [official elaboration of how usePrevious hook works](https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state). – tctco Sep 19 '21 at 11:12

1 Answers1

1

In such case, common pattern is checking if the right argument triggered the useEffect, it can be achieved by comparing the current value with previous one via a reference:

const usePrevious = (arg, compareFn) => {
  const prevState = useRef();

  // Keep ref updated
  useEffect(() => {
    if (compareFn(prevStateSeldom.current, arg)) {
      prevState.current = arg;
    }
  }, [arg]);

  return prevStateSeldom.current;
};

const Parent = (props) => {
  const prevState = usePrevious(stateThatSeldomChange, Object.is);

  useEffect(() => {
    if (prevState !== stateThatSeldomChange) {
      setSomeOtherState(stateThatFrequentlyChange);
    }
  }, [stateThatFrequentlyChange, stateThatSeldomChange]);

  return <Child data={someOtherState} />;
};

This example follows common good practices and known assumptions (for more info see useEffect cases):

  • Each useEffect should have a single responsibility.
  • Hooks called in order, therefore you should extract the logic into custom hook for exposing variable into scope.

This logic commonly implemented by usePrevious hook, you can research receipts for it.

Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
  • You meant `!==` in second effect? Also what is your opinion on my approach? – Giorgi Moniava Sep 19 '21 at 11:05
  • Why `!==`? If they equal means is was triggered by "seldomState" – Dennis Vash Sep 19 '21 at 11:12
  • hm if `stateThatSeldomChange` is same as it's previous value(`prevStateSeldom`), then it didn't change right? I am missing something – Giorgi Moniava Sep 19 '21 at 11:16
  • It didnt change right, thats what we want – Dennis Vash Sep 19 '21 at 11:18
  • yeah but I thought OP wanted to `setSomeOtherState` state when `stateThatSeldomChange` *did change* – Giorgi Moniava Sep 19 '21 at 11:19
  • The first hook updated it, and you checking if thats the one which triggered the hook – Dennis Vash Sep 19 '21 at 11:23
  • Yes but my point is that `prevStateSeldom.current === stateThatSeldomChange` this means it was `stateThatFrequentlyChange` which trigerred the effect, isn't it? OP wanted to listen to other variable IMHO – Giorgi Moniava Sep 19 '21 at 11:25
  • 1
    giorgi is right, though I fully understand what you mean. In my case, the parent component keeps all the data, and each time the parent only provides a small portion to the child. Users should be able to modify this small portion of data (some dots on an SVG canvas, to be specific) through the child component and send the result back to the parent, so the child component needs to render the data when it first receives them. The child component only sends the modifications back and takes care of the SVG canvas itself. As a non-native English speaker, I find it a little difficult to explain... – tctco Sep 19 '21 at 11:26
  • Yes you are right... I need to swap the variables, thanks – Dennis Vash Sep 19 '21 at 11:27
  • 1
    @DennisVash yeah or you can just replace equals sign with not equals – Giorgi Moniava Sep 19 '21 at 11:31