React Part 2 - Component State

Projected Time

5 hours

Prerequisites

Motivation

In the React Intro, we have discussed how React renders HTML.

Now the problem arises: How do we store and change component information we want in the UI? For example, maybe you want a button’s background color to change once it’s been clicked. The solution is to use state.

Objectives

Lesson

Common Mistakes & Misconceptions

  1. The scope of the state is local to the component. This means that the state is restricted within the class only.
  1. Don’t forget to update state immutably.
  1. A component should not change or update its props. Props are values sent by parent component to child component and changing the props will cause inconsistency in prop data. Therefore, it is advisable not to change its own props.

Guided Practice

Now let us understand the use of state with an example.
We will create an increment/decrement counter which includes click functionality and displaying that value. When we click on the increment button, 1 is added to the value and on clicking the decrement button, 1 is subtracted from the value. Initially, the value will be 0.

  1. To create a counter, we will need a value which will change dynamically on clicking the increment/decrement button. Therefore we need to maintain a number inside state. Let us call that number as value. So we will define the state as -
constructor(){
  super();
  this.state = {
    value: 0
  }
}
  1. Now we will create two buttons which will perform the functionality.
<button>Increment</button> <button>Decrement</button>
  1. Create a simple tag to display the number i.e. the value defined in state.
<p>{this.state.value}</p>
  1. That is all which will be displayed on the page. Now we need to implement the functionality when the buttons are clicked.

  2. So, let us create a function which will run when increment button is clicked. To increment the value in the state, we will take the previous value and add 1 to it by using setState function.

addValue = () => {
  this.setState({
    value: this.state.value + 1
  });
};

Note:- setState is a predefined function in React which is used to update the state. The setState function has two function definitions i.e. it can either take an object as a parameter or a function as a parameter.

addValue = () => {
  this.setState((prevState) => {
    return {
      value: prevState.value + 1
    };
  });
};

For now, let us use the object instance only.

  1. Similarly we will create a function which will decrement the value by 1.
subtractValue = () => {
  this.setState({
    value: this.state.value - 1
  });
};
  1. The functions have been created. Now, we just need to associate the functions we have created to the buttons i.e. set the onClick attribute to the button which we have created.
<button onClick="{this.addValue}">Increment</button>
<button onClick="{this.subtractValue}">Decrement</button>
  1. Let us extend this example a bit more by adding lower and upper limit to the value. If the value is 0 , then we cannot reduce the value and when the value becomes 10, we cannot increment the value.
    Thiscanbedonebyhidingthebuttonsoncertainboundaryvalue.
{
  this.state.value < 10 && <button onClick={this.addValue}>Increment</button>;
}
{
  this.state.value > 0 && (
    <button onClick={this.subtractValue}>Decrement</button>
  );
}

That’s all. We have completed our first application in React using React state. To see the complete code Codepen.

Note :- Component will re-render itself only when its state is changed by the component itself and also when the props are changed by parent component. If a component changes its own props , then the component will not be re-rendered. Let us understand this with an example.
Say there is a parent component called App and a Message child component which displays a certain message. App component has a property in state called message with initial value as message. This state property is passed as prop to Message component. Message component has its own state and a property value which is defined in it. There are 3 buttons :-

  1. First button will be defined in App component which will change its state (message).
  2. Second button will be defined in Message component and it will change the state of Message component(value).
  3. Third button will be defined in Message component which will change its own props(message - passed by App component).
class Message extends React.Component {
  constructor() {
    super();
    this.state = {
      value: 'Hello'
    };
  }
  // Function which will change the state of Message Component
  changeState = () => {
    this.setState({
      value: 'World'
    });
  };
  // Function which will change the message prop
  changeProp = () => {
    this.props.message = 'Change Prop message';
  };
  render() {
    return (
      <div>
        <button onClick={this.changeState}> Change Message Comp state </button>
        <button onClick={this.changeProp}> Change prop by Message Comp </button>
        <p>Prop display {this.props.message}</p>{' '}
        <p> Value display {this.state.value}</p>
      </div>
    );
  }
}
class App extends React.Component {
  constructor() {
    //Constructor
    super();
    this.state = {
      message: 'message' // message property defined in state
    };
  }
  // This function will change the state of App Component
  changeState = () => {
    this.setState({
      message: 'New Message'
    });
  };
  render() {
    return (
      <div>
        <button type="button" onClick={this.changeState}>
          {' '}
          Change App Comp State
        </button>
        <Message message={this.state.message} />
        {/* Message Component - prop passed as message */}
      </div>
    );
  }
}

Now let us click this button in sequence defined -

  1. Click on Change App Comp State button. We see that the value of message has been changed to new message as the state of App component changes. Here, the component is re-rendered and the value is passed as prop to Message component and the change is reflected.
  2. Now click on Change Message Comp state button. We see that the value is now world. Again the component changes its state and so it is re-rendered.
  3. Now click on Change prop by Message Comp button. We see that no change happens to the UI.
  4. Now again click on Change Message Comp state button. We see that the value of message prop has been changed to Change Prop message.

How did this happen ?
Well, when we clicked on Change prop by Message Comp button the value of prop got changed. But since, changing its own prop component does not re-render itself, the changes were not displayed. Although the value of prop was changed to Change Prop message, it was not reflected. When we clicked on Change Message Comp state button, the state got updated and the component was re-rendered, therefore the prop changes were also reflected on the UI.

One more thing to see here is that the prop message sent by App component had the value message first and then, it got changed to new message. But now message prop has value Change Prop message. This shows inconsistency. Therefore components follow the rule of pure functions which state that the props (parameters) received by component should not be updated.

To see the complete code Codepen

Independent Practice

For independent practice, let us create a simple game. Say you are a magician having a magic box and 3 random buttons. Out of 3, only 1 button is correct which reveals the text inside the magic box. Children will come to you and choose a button. If the button is correct, any random text which is present inside the box must be displayed and status message should be displayed as you win. If the button chosen is incorrect, then only one message should be displayed as you lose.
UI should contain -

Supplemental Materials