首页 > 解决方案 > React useState Hooks - 在一个状态中管理多个加载状态

问题描述

我正在尝试使用反应挂钩动态管理状态内的多个加载状态。

但是,当我根据 api 调用的结果(成功或错误)更新状态对象时,它会产生一个非常奇怪的结果。

在我下面的代码示例中,单击按钮将触发按钮的加载状态为真。

当我在按钮 1 进行呼叫时单击按钮 1,然后单击按钮 2(这里我只是模拟超时),它们都按预期将加载状态设置为 true。

然后,一段时间后,两个加载状态都设置为 false。

但是,然后两个调用都完成了,按钮 1 加载状态再次设置为 true ......!?

我不确定如何解决这个问题,感谢您的帮助。谢谢你。

https://codesandbox.io/s/usestate-async-timeout-issue-oknvu

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [loading, setLoading] = useState({});
  const handleOnClick = id => {
    setLoading({ ...loading, [id]: true });
    setTimeout(() => {
      // simulate the case for when error is returned after an api call.
      setLoading({ ...loading, [id]: false });
    }, 2000);
  };

  return (
    <div className="App">
      <h1>React UseState: Updating a state object</h1>
      {["1", "2"].map(id => {
        return !loading[id] ? (
          <button key={id} onClick={() => handleOnClick(id)}>
            Item {id}
          </button>
        ) : (
          "Loading..."
        );
      })}
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

标签: reactjsreact-hooks

解决方案


React 中的状态更新不是同步的,当您根据之前的状态更新状态时,这是一个常见的问题。我认为您需要进行以下更改:

  const handleOnClick = id => {
    setLoading(prev => ({ ...prev, [id]: true }));
    setTimeout(() => {
      // simulate the case for when error is returned after an api call.
      setLoading(prev => ({ ...prev, [id]: false }));
    }, 2000);
  };

我已经更改了这两setLoading行以在其更新中使用以前的状态。

您可以在此处阅读有关此内容的更多信息:

https://reactjs.org/docs/hooks-reference.html#functional-updates

何时使用 React setState 回调


推荐阅读