8

我对以下使用 useRef 来存储先前的状态值感到困惑。本质上,它如何能够正确显示先前的值。由于 useEffect 依赖于“value”,我的理解是每次“value”发生变化(即当用户更新文本框时),它会将“prevValue.current”更新为新键入的值。

但这似乎不是正在发生的事情。在这种情况下,步骤顺序是什么?

function App() {
  const [value, setValue] =  useState("");
  const prevValue = useRef('')
  useEffect(() => {
    prevValue.current = value;
  }, [value]);
  return (
    <div>
      <input
        value={value}
        onChange={e => setValue(e.target.value)}
      />
      <div>
        Curr Value: {value}
      </div>
      <div>
        Prev Value: {prevValue.current}
      </div>
    </div>
  );
}
4

3 回答 3

7

好的,虽然这在技术上可行,但它是一种令人困惑的方式,并且可能会在您添加更多内容时导致错误。它起作用的原因是因为在状态更改useEffect运行,并且更改 ref 值不会导致重新渲染。更好的方法是在处理程序期间更新 ref 值,而不是在效果中。但是您发布的代码的工作方式如下:onChange

  1. 最初,两者都是空的
  2. 用户输入一些东西,通过触发状态改变setValue
  3. 这会触发重新渲染,{value}新值也是如此,但由于 ref 尚未更新,{prevValue.current}仍会渲染为
  4. 接下来,在渲染之后,效果会运行,因为它具有value依赖项。所以这个效果会更新 ref 以包含CURRENT状态值
  5. 但是,由于更改 ref 值不会触发重新渲染,因此新值不会反映在渲染的内容中

因此,一旦上述步骤完成,那么从技术上讲,状态值和 ref 是相同的值。但是,由于 ref 更改没有触发重新渲染,它仍然在渲染的内容中显示旧的 ref 值。

这显然不是很好,因为如果有其他东西触发了重新渲染,比如说你有另一个带有连接状态值的输入,那么是的,然后{prevValue.current}会重新渲染为当前{value},然后在技术上是错误的,因为它会显示当前值,而不是以前的值。

因此,虽然它在技术上适用于这个用例,但随着您添加更多代码,它很容易出现错误,并且令人困惑

于 2021-01-19T05:01:25.820 回答
2

useRef()用于在连续渲染中保持值。如果要保留过去的值,请将其放在onChange

<input
    value={value}
    onChange={e => {
       prevValue.current = value;
       setValue(e.target.value)
    }}
   />

这会将其分配给value更改之前的当前状态值,您将不需要useEffect挂钩。

于 2021-01-19T04:56:54.807 回答
1

https://reactjs.org/docs/hooks-reference.html#useref useRef返回一个可变的 ref 对象,其 .current 属性被初始化为传递的参数(initialValue)。The returned object will persist for the full lifetime of the component.

https://reactjs.org/docs/hooks-effect.html useEffect 在每次渲染后运行吗?是的!默认情况下,它运行both after the first render and after every update

所以它发生在顺序步骤中:

1 - Input change (example: "1")
2 - Component re-render
3 - useEffect run and set value ("1") to prevValue.current. This does not make component re-render. At this time prevValue.current is "1".
4 - Input change (example: "12")
5 - Component re-render => show prevValue.current was set before in step 3 ("1")
6 - useEffect run and set value ("12") to prevValue.current. This does not make component re-render. At this time prevValue.current is "12".
... 
于 2021-01-19T05:05:32.920 回答