Javascript 如何在异步函数中批处理setState()调用?

Javascript 如何在异步函数中批处理setState()调用?,javascript,reactjs,async-await,race-condition,setstate,Javascript,Reactjs,Async Await,Race Condition,Setstate,因此,我遇到了一个问题,React没有在异步函数内部批处理多个setState()调用(React通常在异步函数外部自动执行此操作)。这意味着当我的代码运行时,多个连续的setState()调用相互冲突,第一个setState()导致组件更新,第二个setState()发生在组件有足够的时间重新装载之前,我得到错误“无法对已卸载的组件执行React state更新”。我做了一些研究,发现这是预期的行为,但我没有发现如何解决这个问题 这里有一些示例代码(不运行),只是为了可视化我想说的内容。在这种

因此,我遇到了一个问题,React没有在异步函数内部批处理多个setState()调用(React通常在异步函数外部自动执行此操作)。这意味着当我的代码运行时,多个连续的setState()调用相互冲突,第一个setState()导致组件更新,第二个setState()发生在组件有足够的时间重新装载之前,我得到错误“无法对已卸载的组件执行React state更新”。我做了一些研究,发现这是预期的行为,但我没有发现如何解决这个问题

这里有一些示例代码(不运行),只是为了可视化我想说的内容。在这种情况下 setData(response.data); 和 设置加载(假); 冲突并导致错误

我需要一些方法使这两个电话原子化

import React,{useState}来自“React”;
从“@物料界面/核心/按钮”导入按钮;
常量演示=()=>{
const[loading,setLoading]=useState(false);
const[data,setData]=useState({});
const fetchData=async()=>{
设置加载(真);
const response=await callAPI();
如果(response.status==200){
setData(response.data);
}
设置加载(假);
};
返回(
fetchData()}>
获取数据
{JSON.stringify(数据)}

); };
导出默认演示我认为您可以避免将加载作为独立的布尔变量而不是组件状态的一部分。另一种方法是使用
useffect
延迟API调用,直到
加载变量发生更改。你的保险已经办妥了。最后,您可以使用类组件-
setState()
函数接受回调作为第二个参数-这是在挂钩就位之前进行原子状态更改的方式。

您可以将状态批处理到一个复合状态对象中,并执行如下操作

import React, { useState } from "react";
import Button from "@material-ui/core/Button";

const Demo = () => {
  const [demoState, setDemoState] = useState({data: null, loading: false});

  const fetchData = () => {
    setDemoState({...demoState, loading: true});
    callAPI()
      .then( response => handleResponse(response)} );
  }

  const handleResponse = (response) => {
    if (response.status === 200) {
      setDemoState({data: response.data, loading: false});
    } else {
      setDemoState({...demoState, loading: false});
    }
  }

  return (
    <div>
      <Button disabled={loading} onClick={() => fetchData()}>
        Fetch Data
      </Button>
      <p>{JSON.stringify(demoState.data)}</p>
    </div>
  );
};

export default Demo;
import React,{useState}来自“React”;
从“@物料界面/核心/按钮”导入按钮;
常量演示=()=>{
const[demoState,setDemoState]=useState({data:null,load:false});
常量fetchData=()=>{
setDemoState({…demoState,加载:true});
callAPI()
.then(response=>handleResponse(response)});
}
常量HandlerResponse=(响应)=>{
如果(response.status==200){
setDemoState({data:response.data,loading:false});
}否则{
setDemoState({…demoState,加载:false});
}
}
返回(
fetchData()}>
获取数据
{JSON.stringify(demoState.data)}

); }; 导出默认演示;
您可以将加载和数据合并到一个状态。 也不是加载使用状态

例如:

/** status possible values can be: "idle", "pending", "resolved", "rejected"*/

const [state, setState] = useState({status: "idle", data: null})

现在,您可以轻松地更改状态,并根据处理不同事情的方式进行处理

您可以在这里找到答案:您需要使用useEffect钩子来完成此操作。对我来说效果很好:@ChrisG我相信他的示例会很好,它不会在状态更新时卸载/装载任何组件。我想知道OP的实际代码是什么样子的,为什么它如此频繁地重新安装组件,而不仅仅是更新状态/道具和简单地重新加载。我可以通过在xhr运行时卸载组件轻松复制错误。完成后,代码尝试更改未安装组件的状态,这会导致错误。因此,修复方法不是将所有东西批处理在一起,而是在xhr运行时保持组件的装载。实际上,最好使用componentDidUpdate,而不是第二个参数回调。是的,使用
componentdiddupdate
lifecycle函数,而不是使用
setState
callback参数来发出进一步的状态更新。