ReactJs:如何在渲染之前等待componentDidMount()完成?

时间:2017-11-19 11:46:17

标签: reactjs firebase

如何等待异步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()?

5 个答案:

答案 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
}