在 React class 组件中设置动作前后的加载状态

Set loading state before and after an action in a React class component

我有发送动作的函数。我想在操作前后显示一个加载程序。我知道 react 组合传递给 setState 的对象。问题是如何以异步方式更新 属性:

handleChange(input) {
    this.setState({ load: true })
    this.props.actions.getItemsFromThirtParty(input)
    this.setState({ load: false })
}

基本上,如果我将这个 属性 作为应用程序状态的一部分(使用 Redux),一切都很好,但我真的更喜欢只将这个 属性 带到组件状态。

将其余代码包装在第一个 setState:

的回调中
handleChange(input) {
  this.setState({
    load: true
  }, () => {
    this.props.actions.getItemsFromThirtParty(input)
    this.setState({ load: false })
  })
}

有了这个,您的 load 可以保证在 getItemsFromThirtParty 被调用之前被设置为 true 并且 load 被设置回 false

这假设您的 getItemsFromThirtParty 函数是同步的。如果不是,将它变成一个承诺,然后在链式 then() 方法中调用最终的 setState

handleChange(input) {
  this.setState({
    load: true
  }, () => {
    this.props.actions.getItemsFromThirtParty(input)
      .then(() => {
        this.setState({ load: false })
      })
  })
}

您可以执行以下操作...

  1. 更改您的操作以接收 onFetchComplete 回调以及 input
  2. 将 handleChange 更改为 -

    handleChange(input) {
        this.setState({ load: true }, ()=>
            this.props.actions.getItemsFromThirtParty(input,
            ()=>this.setState({ load: false }))
        );
    }
    

这将确保动作处理器代码可以调用回您的状态更改回调,即使它不是以基于承诺的方式编写的。

一个小的更新——对动作创建者使用承诺,async/await 效果很好,与 "then" 链接相比,它使代码更加简洁:

(async () => {
   try {
    await this.props.actions.async1(this.state.data1);
    await this.props.actions.async2(this.state.data2) 
    this.setState({ load: false );
   } catch (e) {
    this.setState({load: false, notify: "error"});
   }
})();

当然是个人喜好问题。

编辑:添加了缺失的括号

您可以将 setState 包装在 Promise 中并使用 async/await,如下所示

setStateAsync(state) {
    return new Promise((resolve) => {
      this.setState(state, resolve)
    });
}

async handleChange(input) {
    await this.setStateAsync({ load: true });
    this.props.actions.getItemsFromThirtParty(input);
    await this.setStateAsync({ load: false })
}

来源:ASYNC AWAIT With REACT

这是 "async-await" setState 的打字稿实现:

async function setStateAsync<P, S, K extends keyof S>(
  component: Component<P, S>,
  state:
    ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) |
    Pick<S, K> |
    S |
    null
) {
  return new Promise(resolve => component.setState(state, resolve));
}

前面的答案不适用于 Hooks。在这种情况下,将第二个参数传递给 setState

时会出现以下错误

Warning: State updates from the useState() and useReducer() Hooks don't support the second callback argument. To execute a side effect after rendering, declare it in the component body with useEffect().

如错误消息所述,在这种情况下您需要使用 useEffect(另请参阅 了解更多详细信息)

我知道这是关于 class 组件的...但是在功能组件中我这样做是为了同步设置状态:

const handleUpdateCountry(newCountry) {
    setLoad(() => true);
    setCompanyLocation(() => newCountry);
    setLoad(() => false);
}

刚刚为我的自动国家/地区检测工作,应该将表单设置为脏。

任何其他答案中都没有提到的一种方法是将操作包装在 setTimeout 中。如果您使用钩子,这也将起作用。

例如:

handleChange(input) {
    this.setState({ load: true })
    setTimeout(() => {
        this.props.actions.getItemsFromThirtParty(input).finally(() => {
            this.setState({ load: false })
        });
    });
}