web-dev-qa-db-fra.com

Utiliser async setState

J'ai une fonction qui a envoyé une action. Je voudrais afficher un chargeur avant et après l'action. Je sais que réagissent en composant l'objet passé à setState. la question est de savoir comment puis-je mettre à jour la propriété de manière asynchrone:

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

Fondamentalement, tout a fonctionné à merveille si je mettais cette propriété dans l'état de l'application (à l'aide de Redux), mais je préfère vraiment mettre cette propriété dans l'état composant uniquement.

20
Chen

Enveloppez le reste de votre code dans le rappel du premier setState:

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

Avec cela, il est garanti que votre load sera défini sur true avant que getItemsFromThirtParty ne soit appelé et que le load ne soit redéfini sur false.

Cela suppose que votre fonction getItemsFromThirtParty est synchrone. Si ce n'est pas le cas, transformez-la en une promesse, puis appelez la dernière setState au sein d'une méthode chaînée then():

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

vous pouvez envelopper le setState dans une promesse et utiliser async/wait comme ci-dessous

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

Source: ASYNC AWAIT With REACT

51
Tejas Rao

Voici ce que vous pouvez faire ...

  1. Changez votre action pour prendre un callback onFetchComplete avec le input.
  2. Changez votre handleChange en -

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

Cela garantira que le code du processeur d'action peut rappeler votre rappel de changement d'état, même s'il n'est pas écrit de manière promise.

1
hazardous

Voici une implémentation TypeScript d'un setState "async-wait":

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

Une petite mise à jour utilisant les promesses pour les créateurs d'action et async/wait fonctionne à merveille et rend le code encore plus propre, comparé au chaînage "d'alors":

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

Bien sûr que c'est une question de goût.

EDIT: Ajout du support manquant

0
Chen