How to wait for async componentDidMount() to finish before rendering?
My 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 calls this async function:
function authUser() {
firebase.auth().onAuthStateChanged(function(user) {
return user
})
}
console.log('in render: ' + this.state.loggedInUser)
How can I make the render method wait for authUser() in componentDidMount?
componentWillMount() method is the least used lifecycle method and called before any HTML element is rendered. If you want to see then check out the example mentioned above, we just need to add one more method.
componentDidMount() only runs once after the first render. componentDidMount() may be called multiple times if the key prop value for the component changes. componentDidMount method is used for handling all network requests and setting up subscriptions during the mounting phase.
You can use the async/await syntax or call the . then() method on a promise to wait for it to resolve. Inside of functions marked with the async keyword, you can use await to wait for the promises to resolve before continuing to the next line of the function.
To wait for a ReactJS component to finish updating, we use a loading state in our react application by use of the conditional rendering of the component. This can be achieved by the use of the useState and useEffect hooks in the functional components.
Don't wait for componentDidMount
to finish before rendering, that would be a misuse of the library, wait for your authUser
to finish.
You can do that by utilising your isAuthenticating
state property in combination with promises
.
function authUser() {
return new Promise(function (resolve, reject) {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
resolve(user);
} else {
reject('User not logged in');
}
});
});
}
You could use your existing isAuthenticating
flag as follows:
componentDidMount() {
authUser().then((user) => {
this.userHasAuthenticated(true);
this.setState({ isAuthenticating: false });
}, (error) => {
this.setState({ isAuthenticating: false });
alert(e);
});
}
Then inside render:
render() {
if (this.state.isAuthenticating) return null;
...
}
This will prevent your component from being added to the DOM until your authUser
function completes.
Your authUser()
function doesn't seem to be set up correctly. You're returning the user object in the callback, but the function itself is not returning anything so var user = authUser();
will always return undefined
.
You'll need to change authUser()
to either call a callback function or return a Promise
that resolves when the user is returned from Firebase. Then set the authentication status to your state once the promise is resolved or the callback is executed. In your render()
function return null
if the authentication has not yet finished.
Async function with callback:
function authUser(callback) {
firebase.auth().onAuthStateChanged(function(user) {
callback(user);
})
}
Using the callback with your component:
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
will always fire after the first render.
either use componentWillMount
or live with the second render, setState
triggers a new render and componentWillMount always fires after the component did mount, i.e it rendered correctly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With