The Programmers Guide To React
Written by Ian Elliot   
Monday, 05 June 2017
Article Index
The Programmers Guide To React
Life Cycle
React the jQuery Way

Class Components

Functional components are a step in the right direction but they don't come with any methods to help work with the lifecycle of a component. What this means will become clear in a moment. A class component is just a component that is defined using a standard JavaScript class. This is the most flexible way to define a component.  

All of the React examples show you how to create a class component using either ES6 classes or using the utility function createReactClass. In fact you can just use a standard JavaScript constructor and prototype inheritance. 

To define a class component you are supposed to use the ES6 class construct:

class Hello extends React.Component{
  methods
}

The methods are the life cycles functions and the only one the component has to have is a render method which returns the element it creates

You can do this without the class construct simply by creating a constructor with the class name and use a new instance of React.Component as the prototype of objects that it creates. For example:

function Hello() {};
Hello.prototype = new React.Component(); Hello.prototype.render = function () {
  return React.createElement(
            "div", null, "Hello World"); };

where we have gone back to the simpler form of the "Hello World" component. The methods don't have to be defined in the prototype, but not doing so isn't as efficient. That is, you could define the function to be:

function Hello() {
   this.render = function () {
    return React.createElement(
             "div",null, "Hello World");
   };
}
Hello.prototype = new React.Component();

Now every instance of the new element will get a its own copy of the render function, whereas with the prototype they all share the same copy.

You create an instance of the element and render it in exactly the same way:

var hello1=React.createElement(Hello,null,null); ReactDOM.render(
        hello1,document.getElementById('root'));

Notice that it is the contructor that you pass to createElement as this corresponds to the ES6 class.  

The createElement can also set a props object on the instance.

For example:

function Hello() {};
Hello.prototype = new React.Component();
Hello.prototype.render = function () {
 return React.createElement(
           "div", null, this.props.hellomessage);
};

Notice the use of this.props.hellomessage. This is automatically set for you if you use:

var hello1 = React.createElement(
          Hello,
         {hellomessage: "Hello World"},
          null);

So far using a class-based component hasn't done anything for us in that there is nothing new. However, what is new is the fact that we can now include methods that React can call. 

But first we have to look a little more closely at createElement and render. 

What Is createElement Doing?

There is a subtle point to notice that really doesn't matter much until you get to class components.

What exacty is createElement Doing?

You might think that it is creating and instance of the class or an instance of the object the constructor creates.

It isn't.

What it does is return the constructor, with props set as a property of the object it creates.

What about the children that you might specify?

These are stored as a property _shadowChildren as an array of constructors or functions or whatever is needed to define the child element. 

So when does the instance get created?

The answer is when you call render the elements constructor is used to create an instance and then the _shadowChildren property is used to create instances of all of the children. These are composed into a tree structure - the virtual DOM and this is used to create real DOM objects which finally appear in the page. 

What happens is a little more subtle in that the React render function compares the virtual DOM with the real DOM and only makes changes that are necessary to make them the same. 

This is an important feature of React and one that is said to make working with the UI much simpler. You don't have to work out what has changed because the render function will do it for you and make the changes necessary - this is something we will have to return to.

Life Cycle

The big advantage of using a class is that you can define methods on it that can be used by React and by other objects. 

There are a number of lifecycle methods that are called when the component is being created and rendered:

 

componentWillMount 

called before render

componentDidMount called after render
componentWillUnmount called just before the component
is removed from the DOM 

 

For example:

function Hello() {};
Hello.prototype = new React.Component(); Hello.prototype.render = function () {
 return React.createElement(
                 "div",
                 null, 
                 this.props.hellomessage);

      };
Hello.prototype.componentWillMount=function(){
      alert("component about to mount");
     };
Hello.prototype.componentDidMount=function(){
      alert("component has mounted");
     };

If you create the element 

var hello1 = React.createElement(
              Hello,
              {hellomessage: "Hello World"},
              null);
ReactDOM.render(
    hello1, document.getElementById('root'));

then the lifecycle functions are called when you render hello1 to the DOM.

There are also methods that you can use that are called when a component updates. 

State

As well as props there is also a state property which is used to change the state of a component. The state property is an object that you can add properties to. Generally you add properties in the constructor and then make use of them in the render function to customize the component. There is a general rule in React that if you don't use a state property in the render function then it probably shouldn't be implement as state. 

For example, suppose we want to show a count of the number of times the Hello World message has been shown - we need a count state property:

function Hello() {
  this.state={count:0};
};

In most cases you would set multiple state properties in the constructor as an initial state. We will use the count as part of the displayed message:

Hello.prototype.render = function () {
 return React.createElement(
    "div", null,
    this.props.hellomessage+" "+this.state.count); };

As we are using count in the render function it is indeed a valid state variable. However we now have to give the rest of the world some way to change it.

Let's suppose that there is a button which calls a changestate function when clicked:

 <button onclick="changestate()">Add One</button>

We need to be able to reference the component in the changestate function. The component is created using:

var hello1 = React.createElement(
                 Hello,
                 {hellomessage: "Hello World"},
                 null);
var helloInst=ReactDOM.render(
                  hello1, 
                  document.getElementById('root'));

As described earlier it is the render function which returns a refernce to the instance created by the constructor. The createElement function returns the constructor plus some additional properties. 

Now we have a reference to the instance we can call its setState function. You should only ever change state properties using setState because this is the only way the change is rendered. That is setState also calls the render function to modify the virtual DOM, then the React render algorithm only changes the real DOM to make it the same. The simplest changestate function is something like:

function changestate(){
 helloInst.setState(
             {count:helloInst.state.count+1});
}

If you try this out you will see that the component is indeed rendered again each time you click the button. 

It would almost certainly to add a method to the component to increment the state. That is:

Hello.prototype.inc=function(){
 this.setState({count:this.state.count+1});
};

and:

function changestate(){
   helloInst.inc();
}

 

reactlogo

 



Last Updated ( Saturday, 30 July 2022 )