Search code examples
reactjsconstructor

react-constructor or componentWillRecevieProps


i use the react for two month, something the react will do constructor, sometime the react will do componentWillRecevieProps. eg:

renderGroups(){
    return this.props.groups.map( (group, i) => {
        return <PickerGroup key={i} {...group} onChange={this.handleChange} groupIndex={i} defaultIndex={this.state.selected[i]} />;
    });
}

this write will do PickGroup constructor every time


Solution

  • It's confusing what you are asking here, but you mentioned React will receive a constructor() function and sometimes it receives a componentWillReceiveProps.

    The purpose of constructors() in React is to initialize state. You initialize state when the component is first created. After that, you use state inside the render() method and then at some point in the future, you update that state with setState().

    Unlike the constructor() function, the render() method is required for every single React component you create, otherwise, React will throw an error. The constructor() function is not required by React, but it is implemented in a class-based component like so:

    class App extends React.Component {
      constructor() {
    
       }
       
      // React says we have to define render()
      render() {
        window.navigator.geolocation.getCurrentPosition(
          (position) => console.log(position),
          (err) => console.log(err)
        );
        return <div>Latitude: </div>;
      }
    };
    

    The constructor() function is particular to the JavaScript language, not to React.

    In a JavaScript class, the constructor() function is the first function that is going to be called anytime an instance of this class is created.

    Anytime we create a new instance of the App component and display it on the screen, this constructor() function is going to be automatically and instantly called before anything else.

    Now, to get to what I believe is your question, this is not the only way to initialize state in React.

    Before I get into the other way to initialize state, you ought to know that when we define the constructor method, it will automatically be called with the props object and yes this is the same props object you may have seen with functional components and with a class-based component it looks like this:

    class App extends React.Component {
      constructor(props) {
    
       }
       
      // React says we have to define render()
      render() {
        window.navigator.geolocation.getCurrentPosition(
          (position) => console.log(position),
          (err) => console.log(err)
        );
        return <div>Latitude: </div>;
      }
    };
    

    When you use the constructor(props) function, there is one required step which is adding super(props);. Why do we have to add this?

    Well, remember, I am talking about class-based components here and keep in mind that as a class-based component our App component above is extending or borrowing functionality from the React.Component base class here.

    This base class has a constructor() function of its own that has some code inside of it, to setup our react component for us.

    When we define a constructor() function inside our App class, we are essentially, overriding or replacing the constructor() function that is inside the React.Component class, but we still need to ensure that all the setup code inside of the React.Component constructor() function still gets called.

    So to ensure that the React.Component’s constructor() function gets called, we call super(props);. super(props) is a reference to the parents constructor() function, that’s all it is.

    We have to add super(props) every single time we define a constructor() function inside a class-based component.

    If we don’t we will see an error saying that we have to call super().

    The entire reason for defining this constructor() function is to initialize our state object.

    So in order to initialize my state object, underneath the super(props); call I am going to write:

    class App extends React.Component {
      constructor(props) {
          super(props);
          
          this.state = {};
       }
       
      // React says we have to define render()
      render() {
        window.navigator.geolocation.getCurrentPosition(
          (position) => console.log(position),
          (err) => console.log(err)
        );
        return <div>Latitude: </div>;
      }
    };
    

    This is our state object that will eventually contain some different pieces of data, some different properties that are very important and relevant to the component being put together.

    So lets say I initialized my state with a property called lat for latitude because this is a geolocation application I am working on, so now my initialized state looks like this:

    class App extends React.Component {
          constructor(props) {
              super(props);
              
          this.state = {lat: null};
       }
    

    I set the value of the lat property to null because I don't have a latitude yet and the latitude value will eventually be a number and in such a case when you know the value will be a number that you don't have yet, you can default it to be null.

    Now, let's say we get an error on this app and we cannot get any data or state at all. We can add another property to state called errorMessage and we can default it to be an empty string like so:

    class App extends React.Component {
              constructor(props) {
                  super(props);
              
          this.state = {lat: null, errorMessage: '' };
       }
    

    Alright, now lets talk about the alternate to the constructor(), by changing this.state and refactoring to state = {lat: null, errorMessage: '' }; and then deleting the constructor() entirely.

    class App extends React.Component {
       state = {lat: null, errorMessage: '' };
    }
    

    This is equivalent to using the constructor() function and I can prove this by going to https://babeljs.io/ and adding the above code to the left panel and seeing how Babel translates it into a constructor() anyway and it translates it back to this.state = like so:

    enter image description here

    If you want to reproduce this yourself, please pay attention to what presets have been ticked on the left hand side of Babel tool.

    Lastly, you mentioned the alternative to the constructor() would be componentWillReceiveProps, but the alternative is actually what I just implemented above.

    Please keep in mind the difference between initializing state and utilizing props. Everything described above is initializing state which is what the constructor() is for.

    In React, you will see different lifecycle methods called, but typically speaking what you will see most of the time is componentDidMount() which automatically gets called one time when the component first gets rendered on the screen and you can place logic in there to do initial data loading and other operations you might want to do one time when the component first boots up.

    The other lifecycle methods you will typically see most often in addition to componentDidMount() is componentDidUpdate() and componentDidUnmount(), but these are not alternatives to initializing state.

    The constructor() function is the only lifecycle method used for state initialization, yes, it is a lifecycle method and so is the render() method.