useRef 存储以前的状态值

useRef to store previous state value

我对下面使用 useRef 存储先前状态值的用法感到困惑。本质上,它如何能够正确显示先前的值。由于 useEffect 依赖于“值”,我的理解是每次“值”发生变化时(即当用户更新文本框时),它会将“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>
  );
}

useRef() 用于在连续渲染中保留值。如果你想保留过去的价值把它放在 onChange:

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

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

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

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

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

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

因此,虽然它在技术上适用于此用例,但随着您添加更多代码,它很容易出现错误,并且难以理解

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

https://reactjs.org/docs/hooks-effect.html 每次渲染后是否使用 Effect 运行?是的!默认情况下,它 运行s 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".
...