I'm working on wrapping my head around all the best practices for dealing with the dependency array in useEffect()
. First, some guidelines (from this blog post & elsewhere):
- If you're calling a function in useEffect that's only used within useEffect, just define it within
useEffect()
. Not needed in deps. - If you're calling a function in useEffect that's used both within & without useEffect, but it doesn't need to access anything from the scope of the component, hoist it outside of the component. Not needed in deps.
- If you're calling function in useEffect that's a dispatcher returned by
useReducer()
or a setter returned byuseState()
, you don't need to include it in dependencies (it doesn't hurt, but you don't have to). - Otherwise, wrap your function in useCallback & add it to useEffect's dependency array.
Is all of this correct? If so, my question:
- If you use useContext or a custom hook to get a setter/dispatcher that was created elsewhere by useState/useReducer, and call it in useEffect, the linter will warn you to add it to the dependency array. I assume that this is because the linter just doesn't know that the function came from useState/useReducer, so it has to err on the side of caution & warn you. Thus, it seems like best practice is to just chuck [dispatch] or [setSomething] in the deps array: just like in point #3 above, it doesn't hurt (it'll still behave like an empty array), and doing so will satisfy the linter. This seems to be the answer here. However, I have seen multiple resources that say you should actually still wrap it in useCallback (i.e. here - I realize this also involves a different issue, but I've definitely seen stableDispatch in quite a few places):
const [state, dispatch] = useContext(MyContext);
const stableDispatch = useCallback(dispatch, []);
useEffect(() => {
stableDispatch(foo)
},[stableDispatch]);
However, that doesn't really seem to do anything. Rather than the linter warning you about deps missing in useEffect, now it just warns you about deps missing in useCallback. So to be more concise, my questions are:
- Are #1-4 accurate?
- In the case of #5, what is the best practice (that also resolves the linter warning, but also doesn't result in running the effect unnecessarily)? Just put 'dispatch' directly in useEffect's deps, or use useCallback, or is there a different approach?
Any clarifications are greatly appreciated.