简体   繁体   中英

React js state and lifecycle

componentDidMount() {
    const user = auth.getCurrentUser();
    this.setState({ user });
  }

I have this code, I think this.setState({ user }); takes a little time, if I want to do some checks immidetly like

<Route
              path="/foo"
              render={props =>
                this.state.user ? (
                  <Bar {...props} />
                ) : (
                  <Redirect to="/login" />
                )
              }
            />

when refreshing the page the user at the beginning is always null. what is the proper solution? do I need to set state at constructor ? or did I do something wrong?

My account got blocked by some down votes questions, the funny thing is I have to re-edit them, even though I already have the accepted answer.I do not understand what's the point to do this.I am so frustrated by this stackoverflow system.

Now, I basically can do nothing but keep editing my questions, and they have all been answered. This is ridiculous !!!

Yes, you should initialise your state in the constructor.

See the React docs example :

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

when refreshing the page the user at the beginning is always null

@Shubham Khatri did explain it really well, in short, just because the render() function is called before the componentDidMount() , hence, the user is always null.

Take a look at this: React lifecycle methods diagram

React 生命周期方法图

And as you can see that, the proper place for setState should be the contructor() cuz it's called before the render() .

However, for api calls why componentDidMount is the better place? why we do not do all set up in constructor ?

I know you're talking about this: https://reactjs.org/docs/faq-ajax.html . The document does say that: You should populate data with AJAX calls in the componentDidMount lifecycle method. This is so you can use setState to update your component when the data is retrieved.

However,in another place , they say:

You may call setState() immediately in componentDidMount() . It will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render() will be called twice in this case, the user won't see the intermediate state. Use this pattern with caution because it often causes performance issues. In most cases, you should be able to assign the initial state in the constructor() instead. It can, however, be necessary for cases like modals and tooltips when you need to measure a DOM node before rendering something that depends on its size or position.

...and also for the case that you need to authenticate because this process depends on the value of the user ( as your design).

The problem in your code is that, componentDidMount is called after render and by the time your user details are fetched and stored in state, your component is ready to redirect to /login since user wan't available. To solve this issue, you need to fetch user details before the initial render and hence constructor is the ideal place to do it

constructor(props) {
   super(props);
   this.state = {
       user: auth.getCurrentUser()
   }
}

The state goes inside the constructor, but only if you need a constructor (eg:to initialize flags). If you don't need a constructor you can just initialize the state outside:

class MyComponent extends Component {
    state = { myState = [] }

    render() {
        const { myState } = this.state
        return (...)
    }
}

You should use the constructor() to initiate state, componentDidMount() for call functions and componentWillReceiveProps() for setState.

  constructor(props) {
    super(props);
    this.state = {
      firstName: "",
      lastName: ""
    };
  }

  componentDidMount() {
    this.props.userProfile();
  }

  componentWillReceiveProps(nextProps, prevProps) {
    this.setState({
      firstName: nextProps.user.firstName,
      lastName: nextProps.user.lastName
    });
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM