Reputation: 1545
I am looking at the documentation from react regarding omitting functions from the list of dependencies because I got this error in my js linter. I have tried to amend my code like the docs show, but I feel like I am missing something, because I still get the same error. I will post my code before and after my attempt. Thanks.
warning React Hook useEffect has a missing dependency: 'handleDocumentScrollThrottled'. Either include it or remove the dependency array react-hooks/exhaustive-deps
Code Before attempted fix
/* Completed useDocumentScrollThrottled utility function */
import { useEffect, useState } from 'react';
import { throttle } from 'lodash';
function useDocumentScrollThrottled(callback) {
const [, setScrollPosition] = useState(0);
let previousScrollTop = 200;
function handleDocumentScroll() {
const { scrollTop: currentScrollTop } = document.documentElement || document.body;
setScrollPosition(previousPosition => {
previousScrollTop = previousPosition;
return currentScrollTop;
});
callback({ previousScrollTop, currentScrollTop });
}
const handleDocumentScrollThrottled = throttle(handleDocumentScroll, 250);
useEffect(() => {
window.addEventListener('scroll', handleDocumentScrollThrottled);
return () =>
window.removeEventListener('scroll', handleDocumentScrollThrottled);
}, []);
}
export default useDocumentScrollThrottled;
Code after attempted fix
...
useEffect(() => {
function doSomething(){
window.addEventListener('scroll', handleDocumentScrollThrottled);
return () =>
window.removeEventListener('scroll', handleDocumentScrollThrottled);
}
doSomething();
}
...
Upvotes: 0
Views: 419
Reputation: 8375
The error will not get resolved, just because you are wrapping the dependency inside another function. The way that's suggested in the docs with the doSomething
exmaple is to move the function out of your hook's scope. This is not possible in your case as your handleDocumentScroll
depends on a setter that's only available in the hook.
Instead you have to:
Add the dependency of handleDocumentScrollThrottled
to your dependency array like so:
useEffect(() => {
//...
}, [handleDocumentScrollThrottled]);
This of course will not work, as handleDocumentScrollThrottled
is reallocated with every render, therefore causing this effect to trigger every single time. That's very likely not what you wanted.
The solution here is to use a memoized value for handleDocumentScrollThrottled, so that it does not change on every re-render:
const handleDocumentScrollThrottled = useMemo(() => {
function handleDocumentScroll() {
const { scrollTop: currentScrollTop } = document.documentElement || document.body;
setScrollPosition(previousPosition => {
previousScrollTop = previousPosition;
return currentScrollTop;
});
callback({ previousScrollTop, currentScrollTop });
}
return throttle(handleDocumentScroll, 250);
}, []);
However, I want to note that (ab)using a setter to set another variable is super hacky and you should probably use a ref
to track your old scroll position instead.
Upvotes: 1