【问题标题】:useRef to store previous state valueuseRef 存储先前的状态值
【发布时间】:2021-04-23 09:43:18
【问题描述】:

我对下面使用 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>
  );
}

【问题讨论】:

    标签: reactjs react-hooks use-ref


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • 哦 k...您指的是该页面上的此声明...。 useEffect 做什么?通过使用这个 Hook,你告诉 React 你的组件需要在渲染之后做一些事情。 React 会记住你传递的函数(我们将其称为“效果”),并在执行 DOM 更新后调用它。
    • 是的,正确,所以useEffect 基本上说“在每次重新渲染之后,一旦更新了 DOM 并且一切都完成了,如果我的依赖项之一发生了变化,请运行此代码”。
    • 是正确的,所以在 React 内部,当更改状态时,状态值会更改,然后组件重新渲染。所以它马上就反映了
    • @Jayce444 - 非常感谢...最后一个相关问题...useEffect 中的返回/清理函数究竟是何时触发的(如果已定义)?
    • @testndtv 组件卸载后,基本上重新创建componentDidUnmount。具体来说,我相信它是在它从 DOM 中移除之后,并且在组件对象被 JS 引擎标记为垃圾回收之前。
    【解决方案2】:

    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".
    ... 
    

    【讨论】:

    • 谢谢...但是对于第 (3) 步,当 useEffect 运行时,“值”不应该等于更新/新值,因此 prevValue.current 也应该是更新/新值吗?这是我的具体问题
    • 例如在第 1 步中输入“1”,然后在第 3 步中,当 useEffect 运行时,value 将为“1”并将设置为prevValue.current,因此prevValue.current 将有值“1”。 useEffect 中的“值”始终是输入的新/更新值。
    • @testndtv 请注意,useEffect 在第一次渲染后和每次更新后运行
    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      • 1970-01-01
      • 2021-11-29
      • 1970-01-01
      • 2021-01-05
      • 2011-12-14
      • 1970-01-01
      相关资源
      最近更新 更多