React React钩子访问闭包变量

时间:2020-09-08 04:33:50

标签: reactjs

当我在React中使用钩子尝试反例时,我想看看异步操作如何在钩子中工作,所以我将代码如下:

function App() {

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

  var times = count>0?"times":"time";
  var txt = count + " " + times;

useEffect(()=>{
  setTimeout(()=>{
    console.log(txt)
  }, 5000)
},[])

  return (
    <div className="App">
      <h1>Clicked {txt}</h1>
      <button onClick={()=>{setCount(1+count);}}>Click</button>
    </div>
  );
}

页面加载后,我多次单击按钮,然后看到计数增加,但是5秒钟后,控制台仍打印出“ 0 time”,我想知道为什么它不访问闭包中的txt变量值范围

谢谢。

function App() {
  if(!window.stack) {
    window.stack = []
  }
  const [count, setCount] = useState({v:0});

  window.stack.push(count);
  var times = count.v>0?"times":"time";
  var txt = count.v + " " + times;

  return (
    <div className="App">
      <h1>Clicked {txt}</h1>
      <button onClick={()=>{setCount({v:1+count.v});}}>Click</button>
    </div>
  );
}

1 个答案:

答案 0 :(得分:3)

每次组件渲染或重新渲染时,App都会再次运行。每次重新渲染都会创建一个新的count变量。

useEffect仅在初始渲染上运行,因为其依赖项数组为[]。在初始渲染中,count0。如果单击该按钮,组件将被重新渲染,但是useEffect中的超时仍然仅关闭初始渲染count变量。

如果您需要类似的东西,您也可以使用ref,对于所有渲染器都有稳定的引用,因此初始渲染器的闭包可以引用在以后的渲染器中发生突变的对象:

const App = () => {
  const [count, setCount] = React.useState(0);
  const times = count > 0 ? "times" : "time";
  const txt = count + " " + times;
  const txtRef = React.useRef(txt);
  txtRef.current = txt;

  React.useEffect(() => {
    setTimeout(() => {
      console.log(txtRef.current);
    }, 5000)
  }, []);

  return (
    <div className="App">
      <h1>Clicked {txt}</h1>
      <button onClick={()=>{setCount(1+count);}}>Click</button>
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>

另一种(可能更糟,更复杂)的选择是在clearTimeout的清理中调用useEffect,并在每个渲染器上调用setTimeout,将剩余的超时时间传递给渲染器。通过检查Date.now()呈现。 (这对于频繁重新渲染的组件效果不佳)