2017-10-11 2 views
1

J'ai une application qui fonctionne et j'essaie juste de régler l'état à loading: true pendant que mon application fait un appel de soumission afin que je puisse afficher un écran de chargement. Parce que je veux m'assurer que je mets l'état avant en faisant l'appel de chargement, j'utilise un rappel. Cependant, je ne vois pas ma mise à jour de chargement avec le code ci-dessous:Le rappel setState ne fonctionne pas comme prévu

submitSecurityAnswer =() => { 
    const { submit, handleError, navigate } = this.props; 
    const { answer } = this.state; 

    this.setState({ loading: true },() => { 
     console.log('setState', this.state) 
     try { 
     submit({ answer, ...this.props }).then(({ errors, status }) => { 
      this.setState({ answer: '' }); 
      if (status && status === 200) { 
      navigate(); 
      } else if (status === 401) { 
      this.setState({ showError: true }); 
      } else { 
      handleError(errors[0]); 
      } 
     }); 
     } catch (err) { 
     console.log(err); 
     } 
    }); 

    this.setState({ loading: false }); 
    }; 

Quand je vérifie mon journal de la console, je vois que l'Etat n'a pas mis à jour et le chargement est toujours faux.

Qu'est-ce qui me manque ici? Cela parce que vous définissez loading à false avant que l'opération asynchrone ne soit terminée.

+0

Si je comprends bien ce que vous essayez de faire correctement votre 'this.setState ({chargement: false})' doit être juste avant ou après 'navigate();' – bennygenel

+0

en fait si vous changez 'this.setState ({answer: ''});' en 'this.setState ({answer: '', loading: false}); 'cela devrait fonctionner aussi – bennygenel

+0

oui, j'essaye de' this.setState ({loading: false}) 'avant le' submit() ' – Turnipdabeets

Répondre

3

Ce qui se passe, parce que vous appelez this.setState({ loading: false }); à la fin de votre fonction. Vous définissez loading: true et loading: false en même temps. Lorsque vous appelez votre callback, la dernière fonction setState est également changée en false.

Vous devez définir l'état de chargement à false après demande a été reçue:

submitSecurityAnswer =() => { 
    const { submit, handleError, navigate } = this.props; 
    const { answer } = this.state; 

    this.setState({ loading: true },() => { 
    console.log('setState', this.state) 
    try { 
     submit({ answer, ...this.props }).then(({ errors, status }) => { 
     this.setState({ answer: '' }); 
     if (status && status === 200) { 
      navigate(); 
     } else if (status === 401) { 
      this.setState({ showError: true, loading: false }); 
     } else { 
      handleError(errors[0]); 
     } 
     }); 
    } catch (err) { 
     console.log(err); 
    } 
    }); 
}; 
2


Il suffit de déplacer this.setState({ loading: false }); à l'intérieur du callback;

Modifier
Comme suivi à votre commentaire:

J'ai essayé de supprimer cela, mais a vu les mêmes résultats

Je n'ai pas dit de l'enlever tout mouvement il à l'intérieur du rappel de setstate.
Ce qui se passe est que vous le définissez à true puis false à la même itération de la pile d'appel et n'attendez pas l'exécution de l'opération asynchrone.

Tenir compte de ce scénario qui est similaire à votre code:
Dans cet exemple, je mis le loading retour false avant l'opération async (setTimeout) est terminée, donc je suis juste remplaçant l'état précédent sans attendre.

class App extends React.Component { 
 
    constructor(props) { 
 
    super(props); 
 
    this.state = { 
 
     loading: false, 
 
     message: '' 
 
    }; 
 
    } 
 

 
    componentDidMount() { 
 
    this.setState({ loading: true },() => { 
 
     console.log(this.state); 
 
     setTimeout(() => { 
 
     this.setState({ 
 
      message: 'we have data' 
 
     }); 
 
     console.log(this.state); 
 
     }, 500); 
 
    }); 
 

 
    this.setState({ loading: false }); 
 
    } 
 

 
    render() { 
 
    const {message, loading} = this.state; 
 
    return (
 
     <div> 
 
     {loading ? <div>Loading...</div> : <div>{message}</div>} 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<div id="root"></div>

Le correctif sera de déplacer le prochain changement d'état à l'intérieur du rappel:
Dans cet exemple, je me suis déplacé la ligne this.setState({ loading: false }); à l'intérieur du rappel après l'opération async est terminée et que ce fixe le comportement indésirable.

class App extends React.Component { 
 
    constructor(props) { 
 
    super(props); 
 
    this.state = { 
 
     loading: false, 
 
     message: '' 
 
    }; 
 
    } 
 

 
    componentDidMount() { 
 
    this.setState({ loading: true },() => { 
 
     console.log(this.state); 
 
     setTimeout(() => { 
 
     this.setState({ 
 
      message: 'we have data' 
 
     }); 
 
     this.setState({ loading: false }); 
 
     }, 500); 
 
    }); 
 

 
    } 
 

 
    render() { 
 
    const {message, loading} = this.state; 
 
    return (
 
     <div> 
 
     {loading ? <div>loading...</div> : <div>{message}</div>} 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<div id="root"></div>

+0

J'ai essayé d'enlever cela mais j'ai vu les mêmes résultats. – Turnipdabeets

+0

je n'ai pas dit supprimer, j'ai dit le déplacer dans la fonction de rappel. voir mes exemples –