0
votes

I am new to react world, I tried to fetch user data from axios call, and tried to get the data before the react's render executed.

How I call this component

<Route path="/users" render={(props) => <User {...props}/>} />

Here is my component class

class User extends React.Component {

    constructor(props) {
        super(props);
        this.state = { authenticated: false }
        this.getCurrentUser = this.getCurrentUser.bind(this);
    }

    componentDidMount(){
        console.log("componentDidMount");
        this.getCurrentUser();
    }

    getCurrentUser(){
        Api.getCurrentUser().then(response => {
        if (response) {
            console.log(response.data.username);
            this.setState({authenticated: true});
        }
      }).catch(error =>{
          this.setState({authenticated: false});
       }
    }

    render() {

        console.log(this.state.authenticated);
        if (this.state.authenticated === false) {
            return <Redirect to={{ pathname: '/login' }}/>
        }
        return (
            <div><Page /> <div>
        );
    }
}

export default User;

The console.log sequence is

false        
componentDidMount
user_one
Warning: Can't perform a React state update on an unmounted component. This is a no-op

The warning makes sense because react already redirect me to login so the user component is not mounted.

I don't understand why componentDidMount is not called before render, because it supposes to change the defaultState through this.setState()...

What am I missing here?

2
Not an answer to your question... (I'm trying to setup a jFiddle to test your code out in the meantime)... but as an aside, consider using React Hooks rather than lifecycle functions. Of course, theres nothing wrong with your approach now... but hooks seems to be the way forward, and I'm sure we'll soon see some of the lifecycle functions being deprecated sooner rather than later.Rohan Büchner

2 Answers

1
votes

ComponentDidMount works the way you described it. It runs immediately after the component is rendered. What you can do is to wrap your Component with a parent component where you have the API call and pass on the isAuthenticated as props to .

Docs for reference

0
votes

As @user2079976 rightly stated, your usage of componentDidMount is correct & it behaves the way it is intended to, but I think you might be getting the wrong impression due to your code execution workflow.

Problem Reason

This issue/warning is generally something to go with when you're updating a component that has unmounted, in your case it's likely the redirect that happens before your api return a result.

More Details:

Not having the full code sample, I had to guess a few of the variables in your setup & I'm unable to get the exact issue on my JsFiddle as you've explained (I think JsFiddle/react.prod swallows the warning messages), but... I'll try to update this fiddle to explain it as much as I can with comments.

// at render this is still false as `state.authenticated` 
// only becomes true after the redirect.
// the code then redirects.... 
// then updates the not yet mounted component & its state 
// which is causing the warning
if (this.state.authenticated === false) {
    return (<Redirect to={{ pathname: '/about' }}/>)
}
return (<div>On Home</div>);

Possible Solution

  • Rather do your auth/logged-in (state) to a higher level/parent component, and have the router decide where to send the user.

  • We have used this exact example in one of our apps (which is an implementation of the above suggestion). It works well for an auth type workflow & is straight from the docs of the Router lib you're using :P https://reactrouter.com/web/example/auth-workflow