1

I use useEffect to listen for a change in location.pathname to auto-scroll back to the top of the page (router) when the route changes. As I have a page transition (that takes pageTransitionTime * 1000 seconds), I use a timer that waits for the page transition animation to occur before the reset takes place. However, on the first load/mount of the router (after a loading page), I do NOT want to wait for the animation as there is no page animation.

Observe the code below, which works exactly as intended:

useEffect(() => {
    const timer = setTimeout(() => {
        window.scrollTo(0,0)
    }, firstVisit.app ? 0 : pageTransitionTime * 1000 )
    return () => clearTimeout(timer)
}, [location.pathname, pageTransitionTime])

The error I face here is that firstVisit.app isn't in the dependency array. I get this error on Terminal:

React Hook useEffect has a missing dependency: 'firstVisit.app'. Either include it or remove the dependency array  react-hooks/exhaustive-deps

firstVisit.app is a global redux variable that is updated in the same React component by another useEffect, setting it to false as soon as the router is mounted (this useEffect has no dependency array, so it achieves it purpose instantly).

// UPON FIRST MOUNT, SET firstVisit.app TO FALSE
useEffect(() => {
    if (firstVisit.app) {
        dispatch(setFirstVisit({
            ...firstVisit,
            app: false
        }))
    }
})

The problem is, when I include firstVisit.app in the dependency array in the first useEffect, the page will auto-reset scroll to (0,0) after pageTransitionTime, affecting the UX.

A bit of Googling lead me to find that I may need to memoize firstVisit.app but I'm not entirely sure how or the logic behind doing so?

singing
  • 65
  • 6

1 Answers1

-2

React's log message tried to say that in your first useEffect hook callback function body you used some value that excluded in the list of dependencies. That's correct, please refer: useEffect Hook

The array of dependencies is not passed as arguments to the effect function. Conceptually, though, that’s what they represent: every value referenced inside the effect function should also appear in the dependencies array. In the future, a sufficiently advanced compiler could create this array automatically.

We recommend using the exhaustive-deps rule as part of our eslint-plugin-react-hooks package. It warns when dependencies are specified incorrectly and suggests a fix.

So, add to the second array parameter of useEffect firstVisit.app, and then check whether this warning/error is gone or not.

Also, you don't need to memoize primitive values, like boolean values (true/false), React is smart enough to not run your callback function again, when your boolean dependency hasn't changed after re-rendering.

[Edit]

If you want to run some logic in useEffect except initial render, i.e. to skip the first time render, you can use:

const isMounted = useRef(false);
    
useEffect(() => {
    if (isMounted.current) {
       doYourTransition();
    } else {
       isMounted.current = true;
    }
}, [deps]);

More complicated one with custom hook, but can be helpful based on your needs and wishes:

const useEffectAfterMount = (cb, deps) => {
    const isMounted = useRef(false);
        
    useEffect(() => {
        if (isMounted.current) {
           cb();
        } else {
          isMounted.current = true;
        }
    }, deps);
}
    
useEffectAfterMount(() => {
   // the logic here runs always, but not on initial render
}, [firstVisit.app]);

I think, you got the idea. Of course, you can move these hooks into a separate file and to reuse them across the project and minimize the amount of code in your current component as well.

flosisa
  • 189
  • 7
  • Thanks. Unfortunately, I may have missed some context in my question. If I add `firstVisit.app` to the dependency array, the error *does* go away, however my page doesn't behave as intended; it reloads after `pageTransitionTime * 1000` because the value of `firstVisit.app` actually changes when that component mounts for the first time. I don't want it to re-render just that first time... – singing Oct 18 '22 at 02:56
  • @singing , ok, I got you. I will edit my answer to add the code that can help you in this case. – flosisa Oct 18 '22 at 04:44