首页 > 解决方案 > 在渲染期间而不是在 useEffect 中更改 ref 的值是否安全?

问题描述

useRef用来保存 prop 的最新值,以便稍后在异步调用的回调(例如 onClick 处理程序)中访问它。我正在使用 ref 而不是放入valueuseCallback 依赖项列表,因为我希望该值会经常更改(当此组件使用 new 重新渲染时value),但 onClick 处理程序将很少被调用,因此不值得分配每次值更改时,都会为元素添加新的事件侦听器。

function MyComponent({ value }) {
  const valueRef = useRef(value);
  valueRef.current = value;  // is this ok?

  const onClick = useCallback(() => {
    console.log("the latest value is", valueRef.current);
  }, []);

  ...
}

React Strict Mode的文档让我相信在其中执行副作用render()通常是不安全的。

因为上述方法[包括类组件render()和函数组件体]可能会被多次调用,因此它们不包含副作用很重要。忽略此规则会导致各种问题,包括内存泄漏和无效的应用程序状态。

事实上,当我使用 ref 访问值时,我在严格模式下遇到了问题。

我的问题是:从渲染函数分配的“副作用”是否有任何顾虑?valueRef.current = value例如,在任何情况下回调会收到一个陈旧的值(或来自尚未提交的“未来”渲染的值)?

我能想到的一种替代方法是useEffect确保在组件渲染后更新 ref,但从表面上看,这看起来没有必要。

function MyComponent({ value }) {
  const valueRef = useRef(value);
  useEffect(() => {
    valueRef.current = value;  // is this any safer/different?
  }, [value]);

  const onClick = useCallback(() => {
    console.log("the latest value is", valueRef.current);
  }, []);

  ...
}

标签: reactjsreact-hooks

解决方案


例如,在任何情况下回调会收到一个陈旧的值(或来自尚未提交的“未来”渲染的值)?

括号是主要关注点。

render当前(和功能组件)调用和实际 DOM 更新之间存在一一对应的关系。(即承诺)

但是很长一段时间以来,React 团队一直在谈论“并发模式”,其中可能会开始更新(render被调用),但随后会被更高优先级的更新中断。

在这种情况下,如果在取消的渲染中更新了 ref,则 ref 可能最终与渲染组件的实际状态不同步。

这一直是假设性的,但刚刚宣布一些并发模式更改将通过API以一种选择加入的方式登陆 React 18 。startTransition(也许还有其他一些)


实际上,这在多大程度上是一个实际问题?很难说。 startTransition是可选的,所以如果你不使用它,你可能是安全的。无论如何,许多参考更新将是相当“安全”的。

但如果可以的话,最好还是谨慎行事。


推荐阅读