react-use icon indicating copy to clipboard operation
react-use copied to clipboard

[Bug report] Remove useLatest

Open SukkaW opened this issue 2 years ago β€’ 3 comments

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.

SukkaW avatar May 09 '22 09:05 SukkaW

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.

Ebuall avatar Jun 17 '22 16:06 Ebuall

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.

zhouzi avatar Dec 27 '22 13:12 zhouzi

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.

pastelmind avatar Jul 13 '23 10:07 pastelmind