setState在useEffect中未更新

时间:2019-12-20 01:21:40

标签: javascript reactjs react-hooks

我有一个简单的组件,如下所示:

import React, {useEffect, useState} from 'react';


function App() {

  const [bus1Points, setBus1Points] = useState();

  const updateBuses = () => {
    setTimeout(updateBuses, 1000);
    console.log(bus1Points);  // Undefined each second
  };

  setInterval(() => {
    console.log('Interval ' + bus1Points); // <-- Prints expected value
  }, 500)

  console.log(bus1Points);
  useEffect(() => {
    setBus1Points('TEST');
    updateBuses();
  }, []);

  return (
    <div style={{ height: '100%', width: '100%' }}>
      {bus1Points}
    </div>
  );
}

export default App;

我不确定为什么每次都未定义它。这是React中的错误吗?为什么updateBuses只得到bus1points的初始值? (请注意,bus1points在用户界面中可以正确呈现)

1 个答案:

答案 0 :(得分:1)

它是未定义的,因为状态更新将反映在下一个渲染中。当您看到它在UI中正确呈现时,是因为状态更新后,ReactJs调用了另一个呈现周期(其中bus1Points具有新值)并再次呈现UI。

每当您执行setBus1Points时,您都在说要批处理一个新的状态值,但是变量bus1Points只是一个值,因此这就是不变的原因

更新

问题在于,当您这样做

const updateBuses = () => {
    setTimeout(updateBuses, 1000);
    console.log(bus1Points);  // Undefined each second
  };

您正在第一个渲染中捕获bus1Points的值(带有闭包)。假设bus1Points的初始值为undefined,您将始终记录该值。这是因为updateBuses引用了一个超出其定义的变量,因此它“捕获”了该值,并且每次通过递归setTimeout都会调用它。

但是,您的setInterval会在每个渲染上执行,因此您正在捕获bus1Points的新值(而且每次添加的日志也越来越多,从而导致内存泄漏)。这不是递归函数,因此它会在每次渲染中捕获新值