Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

useEffect hook - dependencies - re-render issues

Tags:

The first case:
_Let's say I have a prop that is in redux state or in parent state.
_I do not want the useEffect to fire whenever this prop changes,
_But I do need to use the prop within the useEffect.
_React warns me to add the prop to the dependency array, but if I do so, then the useEffect will fire again.

The second case:
_I am using a function within a useEffect,
_But the function is also needed elsewhere.
_Don't want to duplicate the function code.
_React wants me to add the function to the dependency array, but I don't want the useEffect to fire every time that function reference changes.

like image 258
JN Raju Avatar asked Sep 03 '20 20:09

JN Raju


2 Answers

While working with useEffect you should think about closures. If any props or local variable is used inside the useEffect then it is advised to include it inside your dependency array else you will be working with the stale data due to the closure.

Here I present a use case. Inside ComponentUsingRef we are using ref which works as the container. You can find more about it at https://reactjs.org/docs/hooks-reference.html#useref


Advantage of this approach is that you wont be bound to memoize fn in your parent component. You will always be using latest value of function and in the given case it won't even cause firing of useEffect as it won't be on your dependency


const Component=({fn})=>{
    useEffect(()=>{
       fn()
    },[fn])
    .....
    .....
    return <SomeComponent {...newProps}/>
}

const ComponentUsingRef=({fn}){
    const fnRef = useRef(fn)
    fnRef.current = fn // so that our ref container contains the latest value
    useEffect(()=>{
       fn.current()
    },[ ])
    .....
    .....
    return <SomeComponent {...newProps}/>
}

If you want to use abstraction then you should extract your logic inside the custom hook

like image 76
Akash Singh Avatar answered Sep 28 '22 11:09

Akash Singh


If the only issue is the warning then don't worry about it, you can simply disable the rule for your effect and omit the prop from the dependency array if it's the only prop being used in the effect. For effects with multiple dependencies, you can use useRef to store the latest value of the prop without firing the effect, like this:

const Comp = ({someProp, ...props}) => {
  const myProp = useRef(someProp);
  myProp.current = someProp;

  // this effect won't fire when someProp is changed
  React.useEffect(() => {
    doSomething(myProp.current, props.a, props.b);
  }, [props.a, props.b, myProp]);
}

For your second case, I'd probably put that function in a separate file and import it in the components where it'll be used, however, you can use the same pattern for your second case.

like image 43
hackhan Avatar answered Sep 28 '22 11:09

hackhan