React中useLatest的并发安全版本?

有一个常用的实用程序钩子“useLatest”,它返回一个包含输入的最新值的引用。有两种常见的实现:

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

来自https://github.com/streamich/react-use/blob/master/src/useLatest.ts

const useLatest = <T extends any>(current: T) => {
  const storedValue = React.useRef(current)
  React.useEffect(() => {
    storedValue.current = current
  })
  return storedValue
}

来自https://github.com/jaredLunde/react-hook/blob/master/packages/latest/src/index.tsx

第一个版本不适合 React 18 的并发模式,如果在useEffect运行之前(例如在渲染期间)使用,第二个版本将返回旧值。

有没有办法实现既安全又一致返回正确值的方法?

这是我的尝试:

function useLatest<T>(val: T): React.MutableRefObject<T> {
  const ref = useRef({
    tempVal: val,
    committedVal: val,
    updateCount: 0,
  });
  ref.current.tempVal = val;
  const startingUpdateCount = ref.current.updateCount;

  useLayoutEffect(() => {
    ref.current.committedVal = ref.current.tempVal;
    ref.current.updateCount++;
  });

  return {
    get current() {
      // tempVal is from new render, committedVal is from old render.
      return ref.current.updateCount === startingUpdateCount
        ? ref.current.tempVal
        : ref.current.committedVal;
    },
    set current(newVal: T) {
      ref.current.tempVal = newVal;
    },
  };
}

这还没有经过彻底的测试,只是在写这个问题的时候写的,但它似乎大部分时间都有效。它应该比上面的两个版本都好,但它有两个问题:它每次都返回一个不同的对象,并且在这种情况下仍然可能不一致:

渲染 1:

  1. ref1 = useLatest(val1)
  2. 创建 function1,它引用 ref1
  3. 提交(useLayoutEffect 运行)

渲染 2:

  1. 使用最新(val2)
  2. 调用函数1

function1 将使用 val1,但它应该使用 val2。

以上是React中useLatest的并发安全版本?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>