Reputation: 27
So I have a login page that directs users to a profile page in which an asynchronous request is made retrieving a user's id number initiated at the componentDidMount event. Once I get the results back, I setState on the id with the data retrieved.
import React, { Component } from 'react';
import {Navbar} from 'react-materialize';
import {Link, Redirect} from 'react-router-dom';
import helper from '../utils/helper';
import axios from 'axios';
import logo from '../logo.svg';
import '../App.css';
class Profile extends Component {
constructor(props){
super(props);
this.state = {id: null, loggedIn: true};
this.logOut = this.logOut.bind(this);
}
componentDidMount(){
axios.get('/profile').then((results) => {
if(!this._unmounted) {
this.setState({id: results.data})
}
})
}
logOut(event){
axios.post('/logout').then((results) => {
console.log(results);
})
this.setState({loggedIn: false});
}
render() {
if(!this.state.loggedIn){
return <Redirect to={{pathname: "/"}}/>
}
if(this.state.id == null){
return <Redirect to={{pathname: "/login"}} ref="MyRef" />
}
return (
<div>
<Navbar brand='WorldScoop 2.0' right>
<ul>
<li><Link to="#" onClick={this.logOut}>Logout</Link></li>
</ul>
</Navbar>
<h1>Profile Page</h1>
<h2>Welcome {this.state.id} </h2>
</div>
)
}
}
export default Profile;
I am trying to make it so that someone cannot just type the '/profile' path in the url and be taken to a profile page. To do this I tried conditional rendering based on whether an id was retrieved from proper login authentication.That is why if you notice
if(this.state.id == null){
return <Redirect to={{pathname: "/login"}} ref="MyRef" />
}
this will redirect users back to the login page if they do not supply an email and password. I have tried making sure my profile component mounts and unmounts after receiving the data, but I still keeping getting the error message: Can only update a mounted or mounting component. I am confused when the component 'unmounts' .
Upvotes: 1
Views: 630
Reputation: 141
I have succeeded to remove the error message: 'Can only update a mounted or mounting component' by using window.location.replace().
render() {
window.location.replace(`/profile`); // This is how to redirect
return (null);
}
Upvotes: 0
Reputation: 1155
render method is resolving so therefore rerouting you before your axios call finishes, so the solution is to not change locations before your call finishes, usually a loading indicator is used. Also i changed the lifecycle hook from didMount to willMount so the state will reflect before the render.
import React, { Component } from 'react';
import {Navbar} from 'react-materialize';
import {Link, Redirect} from 'react-router-dom';
import helper from '../utils/helper';
import axios from 'axios';
import logo from '../logo.svg';
import '../App.css';
class Profile extends Component {
constructor(props){
super(props);
this.state = {id: null, loggedIn: true, loading: false};
this.logOut = this.logOut.bind(this);
}
componentWillMount(){
this.setState({ loading: true });
axios.get('/profile')
.then((results) => {
// usually data is an object so make sure results.data returns the ID
this.setState({id: results.data, loading: false})
})
.catch(err => {
this.setState({ loading: false, id: null })
})
}
logOut(event){
axios.post('/logout').then((results) => {
console.log(results);
})
this.setState({loggedIn: false});
}
render() {
if(!this.state.loggedIn){
return <Redirect to={{pathname: "/"}}/>
}
if (this.state.loading) return <div>loading...</div>
if(this.state.id == null){
return <Redirect to={{pathname: "/login"}} ref="MyRef" />
}
return (
<div>
<Navbar brand='WorldScoop 2.0' right>
<ul>
<li><Link to="#" onClick={this.logOut}>Logout</Link></li>
</ul>
</Navbar>
<h1>Profile Page</h1>
<h2>Welcome {this.state.id} </h2>
</div>
)
}
}
export default Profile;
Upvotes: 0
Reputation: 387
If you want to check whether component is mounted or unmounted by this._isunmounted, you should make it true in componentWillUnmount.
componentWillUnmount() {
this._isunmounted = true;
}
Upvotes: 1