3

I have this warning in my usage of Reacts useCallback hook.

React Hook useCallback has a missing dependency: 'history'. Either include it or remove the dependency array.eslint(react-hooks/exhaustive-deps

    import { useHistory } from "react-router-dom";

    const MyFunctionalComponent = () => {

       const history = useHistory();

       ....

       const someFunction = useCallback(((param) => {
           history.push({
               search: `?myParam=${param}`
           });
           ....
       }), [history]); <-- Putting history object here removes the warning...

       return (
            <Fragment>
               <Something onClick={() => someFunction(myParam)}
            </Fragment>
       );
    }

Putting history object in the useCallback dependecy param removes the warning, but make no sense to have it as a dependency for this method. This method does not depend on the state of history, it simply calls it method to update the history. Furthermore, i suspect that my parent component will rerender each time history changes, which defeats the purpose of using useCallback.

My question is how to use history object within my useCallback method:

  1. Without having the compiler warning (React Hook useCallback has a missing dependency: 'history'. Either include it or remove the dependency array.eslint(react-hooks/exhaustive-deps)
  2. Without putting a ignore statement for the warning (// eslint-disable-line react-hooks/exhaustive-deps)
  3. Without using window.history since this does not work well with the use of useLocation() hook. History change events are not triggered by window.history. Therefore, cannot use useEffect & useLocation hooks as per example in this article: https://reacttraining.com/blog/react-router-v5-1/?fbclid=IwAR1WHJKKeF0rO_-jW31mRCatWq5o143OvgyURn6R3uGlHNQ_dqs3QQ4ddLs
Stephane
  • 11,056
  • 9
  • 41
  • 51

2 Answers2

1

For those wondering how to fix the issue this is how I resolved it:

const navigateTo = React.useRef(history.push).current;
const handleLogUserOut = React.useCallback(() => {
    // Handle app logic...
    navigateTo('/login');
}, [ navigateTo ]);

React.useEffect(() => {
    handleLogUserOut();
}, [ handleLogUserOut ]);

I basically put history.push method inside of a React.useRef and calling that directly so that I don't have to have a dependency on the whole history object, causing an infinite loop

FrenchMajesty
  • 1,101
  • 2
  • 14
  • 29
0

Did you have any problems from including history in the list of dependencies? That worked fine for me and I didn't notice any extra rendering.

Don't forget that simply changing the state of history (e.g. navigating) is just mutating the existing history object, not creating a different one, so useCallback won't detect a change

Andy
  • 10,412
  • 13
  • 70
  • 95
  • I am using React `17.0.1` and I've noticed that if I include `history` in the dependencies array, it will cause my method to be re-created every time even though I'm only using `history.push` – FrenchMajesty Jun 18 '21 at 23:58