1

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' .

U Rogel
  • 1,893
  • 15
  • 30
dalt25
  • 27
  • 9
  • is your code currently redirecting the user to /login? – Joey Nov 20 '17 at 15:52
  • Yep, so even when I add user credentials I am redirected back to /login with the same error. For some reason, this.setState({id: results.data}). is not setting the state with the retrieved user id . I only have this problem when I add the conditional if(this.state.id == null){ return } – dalt25 Nov 20 '17 at 16:02
  • yup thats because your render method is resolving so therefore rerouting you before your axios call finishes – Joey Nov 20 '17 at 16:03

3 Answers3

1

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;
}
godsenal
  • 387
  • 2
  • 12
  • 1
    react has a built in method `this.isMounted()` but its considered bad practice to check if a component is mounted. https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html – Joey Nov 20 '17 at 15:54
0

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;
Joey
  • 1,075
  • 8
  • 13
  • I'm about to try this, is Loader a component you make yourself? – dalt25 Nov 20 '17 at 16:12
  • yes if you dont have one just use `
    loading...
    `
    – Joey Nov 20 '17 at 16:13
  • Your answer partially works, I'm going to play around with it some more. I can login with user credentials, but when I try to "cheat" and type in '/profile' path in the url, it just takes me to the 'loading' div and stays there. But thank you for getting me one step closer! I had a feeling it was a loading issue as well. – dalt25 Nov 20 '17 at 16:37
  • I added a catch incase API returns an error like a 404, so you should never get stuck on the loading div. – Joey Nov 20 '17 at 16:50
  • Just saw your catch promise above, I must have overlooked it! my apologies. Thank you for your help I'll start to pay more attention to error handling in the future – dalt25 Nov 20 '17 at 19:38
0

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);
}
vomnes
  • 131
  • 6