Comment attendre que async composantDidMount () se termine avant le rendu?
Mon app.jsx:
constructor(props) {
super(props);
this.state = {
loggedInUser: null,
isAuthenticated: false,
isAuthenticating: true
};
}
componentDidMount() {
try {
var user = authUser();
console.log('User: ' + user)
if (user) {
console.log('Is logged in: ' + this.state.loggedInUser)
this.userHasAuthenticated(true);
}
}
catch(e) {
alert(e);
}
this.setState({ isAuthenticating: false });
}
render() {
console.log('in render: ' + this.state.loggedInUser)
// Should execute **after** authUser() in componentDidMount has finished
...
}
composantDidMount appelle cette fonction asynchrone:
function authUser() {
firebase.auth().onAuthStateChanged(function(user) {
return user
})
}
console.log('in render: ' + this.state.loggedInUser)
Comment faire en sorte que la méthode de rendu attende authUser () dans le composantDidMount?
N'attendez pas que componentDidMount
se termine avant de générer le rendu, cela constituerait une mauvaise utilisation de la bibliothèque, attendez que votre authUser
soit terminé.
Vous pouvez le faire en utilisant votre propriété d'état isAuthenticating
en combinaison avec promises
.
function authUser() {
return new Promise(function (resolve, reject) {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
resolve(user);
} else {
reject('User not logged in');
}
});
});
}
Vous pouvez utiliser votre indicateur isAuthenticating
existant comme suit:
componentDidMount() {
authUser().then((user) => {
this.userHasAuthenticated(true);
this.setState({ isAuthenticating: false });
}, (error) => {
this.setState({ isAuthenticating: false });
alert(e);
});
}
Puis à l’intérieur du rendu:
render() {
if (this.state.isAuthenticating) return null;
...
}
Cela empêchera votre composant d'être ajouté au DOM jusqu'à ce que votre fonction authUser
soit terminée.
Si vous souhaitez que le composant ne soit pas rendu, enveloppez votre composant avec un composant d'autorisation personnalisé et ne le restez pas si l'utilisateur n'est pas connecté . Il est déconseillé d'empêcher l'appel de la fonction render
.
Je pense que le problème est que authUser
est asynchrone. Je voudrais utiliser des promesses afin de traiter de manière propre la réponse async. Je ne connais pas l'API de Firebase, mais apparemment, le support proposé a été promis: https://firebase.google.com/docs/functions/terminate-functions
Sinon, vous pouvez utiliser une bibliothèque telle que bluebird et modifier votre fonction authUser pour renvoyer une promesse: http://bluebirdjs.com/docs/working-with-callbacks.html
Si vous n'êtes pas familier avec les promesses, vous devez tout d'abord vous informer sur les principes fondamentaux: https://bitsofco.de/javascript-promises-101/
Votre fonction authUser()
ne semble pas être configurée correctement. Vous renvoyez l'objet utilisateur dans le rappel, mais la fonction elle-même ne renvoie rien, donc var user = authUser();
renverra toujours undefined
.
Vous devrez modifier authUser()
pour appeler une fonction de rappel ou renvoyer une Promise
qui sera résolue lorsque l'utilisateur sera renvoyé de Firebase. Définissez ensuite le statut d'authentification sur votre état une fois la promesse résolue ou le rappel exécuté. Dans votre fonction render()
, renvoyez null
si l'authentification n'est pas encore terminée.
Fonction asynchrone avec rappel:
function authUser(callback) {
firebase.auth().onAuthStateChanged(function(user) {
callback(user);
})
}
Utilisation du rappel avec votre composant:
componentDidMount() {
try {
authUser(function(user) {
console.log('User: ' + user)
if (user) {
console.log('Is logged in: ' + this.state.loggedInUser)
this.userHasAuthenticated(true);
this.setState({ isAuthenticating: false });
}
});
}
catch(e) {
alert(e);
}
}
render() {
console.log('in render: ' + this.state.loggedInUser)
if (this.state.isAuthenticating === true) {
return null;
}
// Rest of component rendering here
}
componentDidMount
tirera toujours après le premier rendu.
soit utiliser componentWillMount
soit vivre avec le deuxième rendu, setState
déclenche un nouveau rendu et composantWillMount est toujours déclenché après le montage du composant, c’est-à-dire qu’il est restitué correctement.