Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug report] Remove useLatest #2328

Open
SukkaW opened this issue May 9, 2022 · 3 comments
Open

[Bug report] Remove useLatest #2328

SukkaW opened this issue May 9, 2022 · 3 comments

Comments

@SukkaW
Copy link

SukkaW commented May 9, 2022

const useLatest = <T>(value: T): { readonly current: T } => {
const ref = useRef(value);
ref.current = value;
return ref;
};

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.

@Ebuall
Copy link

Ebuall commented Jun 17, 2022

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.

@SukkaW SukkaW changed the title [Bug report] Remove [Bug report] Remove useLatest Jun 17, 2022
@zhouzi
Copy link

zhouzi commented Dec 27, 2022

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.

@pastelmind
Copy link

pastelmind commented Jul 13, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants