2

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):

  1. If you're calling a function in useEffect that's only used within useEffect, just define it within useEffect(). Not needed in deps.
  2. 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.
  3. If you're calling function in useEffect that's a dispatcher returned by useReducer() or a setter returned by useState(), you don't need to include it in dependencies (it doesn't hurt, but you don't have to).
  4. Otherwise, wrap your function in useCallback & add it to useEffect's dependency array.

Is all of this correct? If so, my question:

  1. 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.

Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
J23
  • 3,061
  • 6
  • 41
  • 52
  • 2
    In regard to 5, just put it in the dependencies. Like you concluded, it does not negatively impact performance, and in the event that whatever function value the context API provides _changes_ (due to refactoring, etc.) omitting from the dependencies will introduce subtle bugs due to stale closure references. In regard to 4, give me a second to find an answer I've posted before which provides another alternative to consider. – Patrick Roberts May 07 '21 at 23:15
  • 2
    Check out [this](https://stackoverflow.com/a/59669587) and [this](https://stackoverflow.com/a/66417665) for examples of alternatives to `useCallback()`. – Patrick Roberts May 07 '21 at 23:28
  • 1
    Oh, and 1-3 are indeed accurate. – Patrick Roberts May 07 '21 at 23:53
  • Thanks! Want to post an answer so I can accept? :) – J23 May 08 '21 at 02:24

0 Answers0