【问题标题】:Set loading state before and after an action in a React class component在 React 类组件中设置操作之前和之后的加载状态
【发布时间】:2017-09-08 06:31:45
【问题描述】:

我有调度一个动作的函数。我想在操作之前和之后显示一个加载器。我知道组成传递给setState 的对象的反应。问题是如何以异步方式更新属性:

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

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

【问题讨论】:

  • 组件级别的 this.props.dispatch(getItemsFromThirtParty()).then(/* 不管 */) 怎么样?我的意思是,正如 redux 的作者在这里写的那样 - stackoverflow.com/a/33168143/6538824 你真的需要 redux 吗?
  • 那么你打算如何在动作完成后重新渲染组件?
  • Giorgi,这正是重点。我不想将 redux 用于“加载器”状态。当然,我需要 redux 来处理应用程序状态(实际的 DATA)。加载器只属于组件,它不应该是应用程序数据的一部分。我只想在获取数据时显示它,并在收到响应后隐藏它。

标签: reactjs jsx


【解决方案1】:

您可以将 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

【讨论】:

  • 我更进一步,做了const asyncSetState = instance => newState => new Promise(resolve => instance.setState(newState, resolve));,您可以在任何组件中使用它......await asyncSetState(this)({ mystuff: false });
  • 或者保持它简单 :-) 你可以将它添加到你的工具中以重用export function setStateAsync(state, that) { return new Promise((resolve) => { that.setState(state, resolve); }); } 并调用await setStateAsync(<new state>, this)
【解决方案2】:

将其余代码包装在第一个 setState 的回调中:

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

这样,您的load 保证在调用getItemsFromThirtParty 之前设置为true,并将load 设置回false

这假设您的 getItemsFromThirtParty 函数是同步的。如果不是,则将其转换为 Promise,然后在链式 then() 方法中调用最终的 setState

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

【讨论】:

  • 导出一个函数会返回一个接受调度的函数,该函数返回在 setState 中解析的 Promise。就像魔术一样工作!谢谢詹姆斯!
  • 不要忘记在 catch 块中将 load 设置为 false,以防 Promise 被拒绝。
  • 如何在useState中设置?
【解决方案3】:

这是“async-await”setState 的 typescript 实现:

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));
}

【讨论】:

  • 我收到错误:Argument of type '(value: unknown) =&gt; void' is not assignable to parameter of type '() =&gt; void'.ts(2345)
【解决方案4】:

这是你可以做的......

  1. 将您的操作更改为在 onFetchComplete 回调以及 input 中执行。
  2. 将您的句柄更改为 -

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

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

【讨论】:

  • 有趣。但其实更喜欢承诺时尚。感谢您的建议
  • 是的,Promise 效果更好。在像 Reflux 这样的场景中,很难从动作中返回结果,所以你不能在那里使用 Promise。此外,您必须记住抓住它们,否则您可能会永远运行微调器:)。让一些行动返回非承诺,而另一些承诺也应该明确标识,比如他们的名字。
  • 捕捉错误——不容错过。并且不能同意更多关于命名!
【解决方案5】:

之前的答案不适用于 Hooks。在这种情况下,将第二个参数传递给 setState 时会出现以下错误

警告:来自 useState() 和 useReducer() Hooks 的状态更新不支持第二个回调参数。要在渲染后执行副作用,请在组件主体中使用 useEffect() 声明它。

如错误消息所述,在这种情况下,您需要改用 useEffect(有关更多详细信息,另请参阅 this discussion

【讨论】:

    【解决方案6】:

    一个小的更新——对动作创建者和 async/await 使用 Promise 效果很好,与“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"});
       }
    })();
    

    当然,这是一个品味问题。

    编辑:添加缺少的括号

    【讨论】:

    • this.setState({ load: false );移动到finally如果你不需要通知错误,你的代码会更简洁;)。
    【解决方案7】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2020-01-25
      • 2021-10-31
      • 1970-01-01
      • 1970-01-01
      • 2020-01-19
      • 2019-01-19
      • 2015-08-16
      • 2021-03-25
      • 2021-07-20
      相关资源
      最近更新 更多