首页 > 解决方案 > 如何解决 React Hook 关闭问题?

问题描述


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

它是否正确?

标签: javascriptreactjsclosuresuse-state

解决方案


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>
  );
}

Codesandbox中的工作演示

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


推荐阅读