react
react copied to clipboard
Feature request: dealing with dependencies in custom React hooks
Let's suppose that I'm trying to define a custom hook using useEffect (the same comment applies for other hooks relying on dependencies such as useCallback, useMemo, useLayoutEffect, etc...):
import {useEffect} from "react"
export const useWindowScroll = (dependencies) => {
useEffect(() => {
window.scrollTo(0,0)
}, dependencies)
}
This would be the ideal code to write to make this hook re-usable:
- It encapsulates the exact business logic, which is to scroll back to the top of the page when one of the dependencies change
- It works using similar syntax to a standard React hook, so provides a nice interface to the developer
- It's as simple as it gets: do the exact thing you've always been doing with the standard hooks.
However, this leads to problems because React complains about the 'dependencies' array. There are different ways one could go about solving this, but they all feel sort of hacky and unnatural to me, one of them being replacing 'dependencies' by 'JSON.stringify(dependencies)' (suggested by Dan Abramov according to a quote I cannot find anymore). It works, but it looks strange to remember that this trick needs to be done.
Something else that would also be practical would be to be able to write [someOtherVariable, ...dependencies] in that second argument of a useEffect/useCallback/use(...), without having to wrap it in a JSON.stringify.
Is there anything that we could do in React itself to make the API for custom hooks simpler when it comes to dependencies?
there is a problem of using just [dependencies]?
like
import {useEffect} from "react"
export const useWindowScroll = (dependencies) => {
useEffect(() => {
window.scrollTo(0,0)
}, [dependencies])
}
there is a problem of using just
[dependencies]?like
import {useEffect} from "react" export const useWindowScroll = (dependencies) => { useEffect(() => { window.scrollTo(0,0) }, [dependencies]) }
I tested it on a similar example, and strangely enough for me it seems to work, and I don't understand why. But doesn't that nest the arrays though? Like if the original dependencies array was [firstVariable, secondVariable] then the dependencies of the useWindowScroll become [[firstVariable, secondVariable]], so how does React statically check for dependencies change? I thought this was dangerous because arrays are mutable, so after each state change, the dependencies array actually is different from the previous one because we get a new copy of the same array (i.e. an array with the same values but with a different id, which explains why [] == [] and [] === [] both return false in JavaScript). So I don't know why this works!
there is a problem of using just
[dependencies]?like
import {useEffect} from "react" export const useWindowScroll = (dependencies) => { useEffect(() => { window.scrollTo(0,0) }, [dependencies]) }
This would cause the useEffect to be called on every render if you were to call the custom hook this way:
const MyComp = ()=>{
useWindowScroll(['dep1'])
return <></>
}
unless dependencies is wrapped in useMemo or is declared outside the component
You could use
export const useWindowScroll = (dependencies) => {
const dependenciesRef = useRef(dependencies)
useEffect(() => {
// use the dependencies using `dependenciesRef.current`
window.scrollTo(0,0)
}, [])
}
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you!