Home > Software engineering >  How to deal with exhaustive-deps when a required dependency must not trigger a call on update?
How to deal with exhaustive-deps when a required dependency must not trigger a call on update?

Time:08-08

In my functional React component, I have a function that is used both on component mount and in some child event:

const [count, setCount] = useState(0);
  
const myFunction = useCallback(() => {
    // do something with count, such as a fetch or console.log for example
}, [])

useEffect(() => {   
    myFunction()
}, [myFunction])

return (
    <button onClick={myFunction}>
        myButton
    </button>
)

myFunction must be called on mount and when the button is clicked. However, the classic React way of doing this implies to declare count as a dependency in useCallback, which would trigger a call of myFunction each time count is updated by another part of the program, which I do not want. count must be able to be updated without triggering myFunction.

I cannot find a clean solution for doing this. Is there one? Or should I write my code a different way? What's the best way to deal with this situation?

CodePudding user response:

For your specific example, there's a simple solution. Instead of using the count state variable inside of useCallback, and therefore making it a dependency of the useCallback hook, you could just use the callback parameter of the state updater function. So instead of:

const myFunction = useCallback(() => {
    setCount(count   1)
}, [])

You could write it like this:

const myFunction = useCallback(() => {
    setCount((prevCount) => prevCount   1)
}, [])

Another way, for more complex instances, would be to use the useReducer hook instead of useState. Since you would be using useReducer's dispatch function to update the state, there wouldn't any need to have the state as a dependency in the useCallback hook.

const [count, dispatch] = useReducer((state, action) => {
  switch (action.type) {
    case "INCREMENT":
      return state   action.by;

    default:
      return state;
  }
}, 0);

const myFunction = useCallback(() => {
  dispatch({ type: "INCREMENT", by: 1 });
}, []);

useEffect(() => {
  myFunction();
}, [myFunction]);

return (
  <div>
    <p>{count}</p>
    <button onClick={myFunction}>myButton</button>
  </div>
);

CodePudding user response:

Use React functional updates for setState:

setCount(count => count   1);

This way you do not need to add count to dependencies.

  • Related