1

Consider the following example (wrote it from memory, so could have some issues):

export function App(props) {
    const [howManyTimesUserHasDraggedMap, setHowManyTimesUserHasDraggedMap] = useState(0);
    const [mapCenter, setMapCenter] = useState<LatLng>(new LatLng(0, 0));
    const [shouldLog, setShouldLog] = useState(true);

    const handleCenterChange = (newCenter: LatLng) : void => {
        setMapCenter(newCenter);
    }

    useEffect(() =>
    {
        setHowManyTimesUserHasDraggedMap((prev) => prev + 1);

        if(shouldLog)
            console.log('Updated map drag count');
    } [mapCenter]);

    return (
        <MapComponent onCenterChange={handleCenterChange} />
    );
}

The point here is that we have, for example, some component called Map which shows Google Maps in a modal and user can interact with the map by dragging and zooming it.

Lets say that I want to keep track of how many time the user has dragged the map, which is basically the same as changing the center of it. The Map component takes onCenterChange prop and I give it a function which updates the mapCenter state with the newCenter whenever the center changes.

Now this example is a bit dumb (I could do all this in the handleCenterChange, but that's beside the point), but for whatever reason I want to use useEffect here to increment the number of drags whenever the mapCenter state changes, so I put mapCenter to the dependency array because that seems like the logical thing to do. I do also have an if-statement there which checks if shouldLog is true and console.logs something irrelevant to the console if so.

Now the issue here is that the dependencies for that useEffect are not exhaustive since shouldLog is missing from the dependency array and I'm getting warnings left and right. I then go read some documentation and there are warnings and alerts everywhere to ALWAYS INCLUDE ALL THE DEPENDENCIES.

Reactjs useEffect deps warning

But that doesn't really make sense here now does it? Why should I trigger that useEffect if my shouldLog-state changes - that doesn't mean that the mapCenter has changed. shouldLog's value is only relevant if the center changes.

My current understanding is that I can use useEffect to basically subscribe into certain events, such as when the component mounts, when the component unmounts, when the component re-renders or when something in the dependency array changes. So in this case I am subscribing to an event that fires when mapCenter changes and that is when it should ever fire. When the event fires though, it just happens to check what it should do regarding to logging, but the change in logging isn't a reason to fire the event.

So is my understanding completely wrong here or what is going on?

Swiffy
  • 4,401
  • 2
  • 23
  • 49
  • 1
    Use the dependencies that make sense for your use. You are right about your use of `shouldLog` not being prone to closure or sideeffects in the rest of the component, so it can safely be excluded. One often uses useEffect with an empty dependency to force running only on mount whtich triggers the same linting error but that doesn't make it wrong. Linting brings attention to possible deviations from best practice but is not the bottom line. – pilchard Jun 09 '22 at 17:44
  • The linter rule is one thing, but even the official documentation says to make sure that the array includes all values that change over time and that are used by the effect and that's all I've ever heard about this. I use non-exchaustive deps all the time, but this makes me worried, since I haven't seen any talk about situations where a dependency is relevant to what the useEffect does, but not for when it should fire. – Swiffy Jun 09 '22 at 18:06
  • see: [Understanding the React Hooks 'exhaustive-deps' lint rule](https://stackoverflow.com/questions/58866796/understanding-the-react-hooks-exhaustive-deps-lint-rule) for discussion of useEffect as 'subscription' vs 'side-effect'. – pilchard Jun 09 '22 at 18:09

0 Answers0