react-use
react-use copied to clipboard
[Bug report] Remove useLatest
https://github.com/streamich/react-use/blob/3685b7502a4d1980953deed11c3dee31b220c89d/src/useLatest.ts#L3-L7
Although the current React documentation doesn't mention it, according to the React beta documentation:
Do not write or read
ref.current
during rendering. React expects that the body of your component behaves like a pure function:
- If the inputs (props, state, and context) are the same, it should return exactly the same JSX.
- Calling it in a different order or with different arguments should not affect the results of other calls.
Reading or writing a ref during rendering breaks these expectations.
When you break these rules, your component might still work, but most of the newer features weβre adding to React will rely on these expectations.
When I was writing something like this, I would wrap it in useEffect
without thinking. But I don't see how idempotent writing could hurt here.
Reading from ref is a completely different story.
Wouldn't it be fixed by a useLayoutEffect
?
const useLatest = <T>(value: T): { readonly current: T } => {
const ref = useRef(value);
useLayoutEffect(() => ref.current = value, [value]);
return ref;
};
EDIT: it's working slightly differently though so not sure it would cover all use cases and it'd probably warrant a breaking change.
I use these two hooks frequently in my projects:
interface LatestRef<T> {
readonly current: T
}
function useLatestRef<T>(value: T): LatestRef<T> {
const ref = useRef(value)
useEffect(() => {
ref.current = value
})
return ref
}
function useLayoutLatestRef<T>(value: T): LatestRef<T> {
const ref = useRef(value)
useLayoutEffect(() => {
ref.current = value
})
return ref
}
These hooks update the ref value at different timings, which can be important when the ref is used by another useEffect()
or useLayoutEffect()
.
Since people rely on useLatest()
, perhaps we could deprecate it (with a warning that mentions concurrency and tearing problems) and add these two hooks as separate APIs? This would also pair nicely with #1965.