【问题标题】:React: using state in a passed callback function to a class constructor doesnt use latest version of state [duplicate]反应:在传递给类构造函数的回调函数中使用状态不使用最新版本的状态[重复]
【发布时间】:2021-04-07 05:31:01
【问题描述】:

抱歉标题令人困惑,但这是发生了什么:

MyComponent 中,我使用useState React 挂钩设置count 状态。 一旦组件挂载(即useEffect 没有依赖项),我将实例化两个MyClass 对象,第一个参数作为增加状态的回调函数,第二个参数是timeOut 周期以调用回调功能。

MyClass 的第一个实例在 1000 毫秒内调用回调并为 count 设置新值,更新后将记录在第二个 useEffect 中。

但是,当MyClass 的第二个实例调用回调(在timeOut 3000 毫秒的周期之后)并尝试增加count 值时,它使用count 的状态,从@987654335 开始@ 已实例化(为 0),因此它将 count 递增到 1(想要的行为是递增到 2,因为 MyClass 的第一个实例已经将 count 从 0 递增到 1)

这不是与setState 的异步行为相关的问题,因为很明显,count 的第一次更新发生在第二个实例再次尝试更新它之前(第二个useEffect 在@987654342 时被调用@ 状态已更新,您可以从控制台日志消息中看到,这是在 MyClass 的第二个实例调用回调之前发生的。

JSFiddle 链接: https://jsfiddle.net/hfv24dpL/

总之,我认为问题在于回调函数中的count 状态是回调函数传递给MyClass 构造函数时count 状态的副本。

此示例的解决方案可能是仅在 count 状态更新时(在第二个 useEffect 中)实例化 MyClass 的第二个实例,但这不是我正在寻找的解决方案。

另一个解决方案是使用setCount(prevCount => prevCount + 1) 来增加count,但这在我的实际应用程序中不可行(MyComponentMyClass 是我为这个问题编写的真实 React 应用程序的骨架示例) .

我希望能够在组件挂载时一起实例化类(在第一个useEffect),并让回调引用count 的最新版本。

这个 ^ 是否有解决方案,或者没有办法绕过这个 javascript 和 React 实现?感谢您阅读所有这些,我知道它很长:)

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

class MyClass{

  constructor(callback, timeOut){

    // call callback in timeOut milliseconds
    this.timeOutId = setTimeout(() => {
      callback();

      }, timeOut)

  }

  clearTimeOut(){

    clearTimeout(this.timeOutId);

  }

}


function MyComponent(){

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

  // component did mount
  useEffect(() => {
    let myClass1 = new MyClass(funcToCallback, 1000);
    let myClass2 = new MyClass(funcToCallback, 3000);

    // when component unmounts, clear the timeouts of MyClass instances
    return () => {

      myClass1.clearTimeOut();
      myClass2.clearTimeOut();

    }
  }, []);


  // counter state updated
  useEffect(() => {

    console.log("COUNT UPDATED TO: ", count);

  }, [count])

  // get counter and increment it by 1
  function funcToCallback(){

    console.log("CALLBACK CALLED");
    let newCount = count + 1;
    incCount(newCount);

  }

  function incCount(newCount){

    console.log("NEW COUNT: ", newCount);
    setCount(newCount);

  }

  return (
    <div>
      COUNT: { count }
    </div>
  )

}

【问题讨论】:

  • 第一个问题很好!

标签: javascript reactjs react-state react-state-management


【解决方案1】:

使用的funcToCallback是组件初始挂载中的那个,当count为0时。用const声明的变量不会改变,useEffect回调只被调用一次, funcToCallback 关闭的 count 永远保持为 0。

最简单的解决方法是改用 setter 的函数版本,这将为您提供先前的状态作为参数 - 然后您可以增加它。改变

  function incCount(newCount){
    console.log("NEW COUNT: ", newCount);
    setCount(newCount);
  }

  function incCount(){
    setCount((lastCount) => {
      console.log("NEW COUNT: ", (lastCount + 1));
      return lastCount + 1;
    });
  }

【讨论】:

  • 你好乔纳斯,感谢分享!是的,我知道关闭问题,并且我提供了与您在帖子结尾处所做的相同的答案,但是我正在寻找另一种解决方案,因为 useState 的函数版本在我的实际应用程序中不是一个可行的解决方案。 (我写这个代码作为闭包问题的一个例子,我的应用程序处理闭包问题,但在不同的上下文中)。
猜你喜欢
  • 2023-01-16
  • 2020-11-16
  • 1970-01-01
  • 2021-07-27
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
  • 2022-01-26
  • 2019-03-08
相关资源
最近更新 更多