如何解决 React Hook 关闭问题?

IT技术 javascript reactjs closures use-state
2021-03-28 14:30:59

import React, { useState} from "react";
import ReactDOM from "react-dom";

function App() {
  const [count, setCount] = useState(0);

  function handleAlertClick(){
    return (setTimeout(() => {
  alert("You clicked on: " + count);
}, 3000))
  }


  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
      <button onClick={handleAlertClick}>Show alert</button>
    </div>
  );
}

我只想知道这是否像我认为的那样工作,或者是否有更好的解释!

每当setState调用方法时,状态都会获得一个新的引用。这意味着原始状态没有新值,而是我们用新值创建了一个新状态。当我们点击第二个按钮时,事件处理函数捕获原始状态的引用。即使我们多次单击第一个按钮,当显示警报时,它也会显示事件处理程序捕获其引用的状态值。

这个对吗?

1个回答

alert显示过时值的原因count是因为传递给的回调setTimeout引用了count闭包捕获的过时值这通常称为stale-closure

在初始渲染时,匿名函数作为回调传递以setTimeout捕获countas的值0,当按钮show alert被单击时,回调将排队但具有过时的 count 值。

在上述情况下,在警报消息中显示更新的计数值并修复过时关闭问题的最简单解决方案是使用ref.

function App() {
  const [count, setCount] = useState(0);

  const latestValue = useRef(count);

  const handleAlertClick = () => {
    setTimeout(() => {
      alert(`count is: ${latestValue.current}`);
    }, 3000);
  };

  return (
    <div>
      <p>You clicked {count} times</p>
      <button
        onClick={() => {
          setCount(prev => {
            latestValue.current = prev + 1;
            return prev + 1;
          });
        }}
      >
        Click me
      </button>
      <button onClick={handleAlertClick}>Show alert</button>
    </div>
  );
}

代码沙盒中的工作演示

Hooks 严重依赖闭包来工作,所以你很可能会遇到关于stale-closures 的问题这是一篇关于过时闭包在使用 react-hooks 时如何产生问题的好文章,并演示了如何在某些情况下解决一些问题。

它与国家无关。该行为完全与闭包的工作方式以及闭包如何捕获过时的变量有关。这个问题可以很容易地在一个函数中重现。这不限于反应。请参阅文章中提供的一个示例
2021-05-22 14:30:59
好的,我刚刚意识到当我说引用时我们对它的不同之处我的意思是闭包捕获变量的引用以在它想要使用该引用的值时返回给它!我们处理的是闭包不捕获值而是捕获变量(我的意思是在我的情况下是引用)!
2021-05-27 14:30:59
我不认为这是关于捕获计数的值,而是关于捕获计数变量的引用,你同意我的观点吗?请阅读我在问题代码下方所说的内容!
2021-06-02 14:30:59
请注意,useRef创建的对象将在组件的整个生命周期内持续存在,并且 React 将在每次渲染时为您提供相同的 ref 对象这是有效的,因为通过引用内存中的同一个对象,任何回调,无论其定义或执行时的范围如何,都指向同一个对象,从而消除了陈旧的引用。
2021-06-04 14:30:59
这不仅仅是捕获过时的变量,如果是这种情况,为什么值变量的值会被更新?这完全是关于引用的问题是,每当我们调用 inc() 函数时,消息变量都会用内存中的新地址初始化,这意味着闭包会捕获第一条消息的引用,这就是为什么当我们调用 log 函数时它返回值1.如果我们尝试用 value 变量初始化顶部的 message 变量将解决问题,因为我们不需要在任何时候调用 inc 函数时初始化 message 变量!!
2021-06-05 14:30:59