首页 > 解决方案 > 反应:在传递给类构造函数的回调函数中使用状态不使用最新版本的状态

问题描述

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

MyComponent中,我正在使用React 钩子设置count状态。useState一旦组件安装(即useEffect没有依赖关系),我将MyClass使用第一个参数作为增加状态的回调函数来实例化两个对象,第二个参数是timeOut调用回调函数的周期。

的第一个实例MyClass在 1000 毫秒内调用回调并设置 的新值count,该值一旦更新,就会记录在第二个中useEffect

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

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

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

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

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

另一种解决方案是使用setCount(prevCount => prevCount + 1)to increment count,但这在我的实际应用程序中是不可行的(MyComponent并且MyClass是我为这个问题编写的真实 React 应用程序的骨架示例)。

我希望能够在组件挂载时一起实例化类(在 first 中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>
  )

}

标签: javascriptreactjsreact-statereact-state-management

解决方案


使用的是组件初始挂载的funcToCallback那个,什么时候count为0。用声明的变量const不会改变,useEffect回调只被调用一次,关闭的count那个funcToCallback永远保持在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;
    });
  }

推荐阅读