如何解决 React Hook 关闭问题?

A2u*_*2ub 13 javascript closures reactjs use-state


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>
  );
}
Run Code Online (Sandbox Code Playgroud)

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

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

这样对吗?

sub*_*tra 16

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>
  );
}
Run Code Online (Sandbox Code Playgroud)

代码沙盒中的工作演示

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