如何等待异步componentDidMount()在渲染之前完成?
我的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
...
}
componentDidMount调用此异步函数:
function authUser() {
firebase.auth().onAuthStateChanged(function(user) {
return user
})
}
console.log('in render: ' + this.state.loggedInUser)
如何让render方法等于componentDidMount中的authUser()?
答案 0 :(得分:13)
在呈现之前不要等componentDidMount
完成,这将是对图书馆的误用,等待authUser
完成。
您可以将isAuthenticating
州财产与promises
结合使用来实现这一目标。
function authUser() {
return new Promise(function (resolve, reject) {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
resolve(user);
} else {
reject('User not logged in');
}
});
});
}
您可以使用现有的isAuthenticating
标记,如下所示:
componentDidMount() {
authUser().then((user) => {
this.userHasAuthenticated(true);
this.setState({ isAuthenticating: false });
}, (error) => {
this.setState({ isAuthenticating: false });
alert(e);
});
}
然后在渲染中:
render() {
if (this.state.isAuthenticating) return null;
...
}
这将阻止您的组件在authUser
函数完成之前添加到DOM中。
答案 1 :(得分:0)
componentDidMount
将始终在第一次渲染后触发。
要么使用componentWillMount
要么使用第二个渲染,setState
会触发一个新的渲染,componentWillMount总是在组件安装后触发,即它正确渲染。
答案 2 :(得分:0)
如果您希望组件不被渲染,请使用一些自定义授权组件包装组件,如果用户未登录,则不渲染组件。
尝试阻止render
函数调用是不好的做法。
答案 3 :(得分:0)
我认为这里的问题是authUser
是异步的。我会使用promises来以干净的方式处理异步响应。我不知道firebase API,但显然支持承诺:https://firebase.google.com/docs/functions/terminate-functions
否则你可以使用像bluebird这样的库并修改你的authUser函数来返回一个承诺:http://bluebirdjs.com/docs/working-with-callbacks.html
如果您不熟悉承诺,首先应该阅读基本原则:https://bitsofco.de/javascript-promises-101/
答案 4 :(得分:0)
您的authUser()
功能似乎未正确设置。您将在回调中返回用户对象,但函数本身并未返回任何内容,因此var user = authUser();
将始终返回undefined
。
您需要更改authUser()
以调用回调函数或返回从Firebase返回用户时解析的Promise
。然后在解析promise或执行回调后将身份验证状态设置为您的状态。如果身份验证尚未完成,请在render()
函数返回null
。
带回调的异步功能:
function authUser(callback) {
firebase.auth().onAuthStateChanged(function(user) {
callback(user);
})
}
对组件使用回调:
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
}