State

web
mobile

Author: Dawid Adach

-

1. State


In the last lesson, we learned how to pass data to our components using props (properties). We've also learned that props cannot be overwritten within the component. In order to keep track of a component's internal state/configuration/setting React developers created a special variable called state


            state = {
                time: "10:00",
                title: "My state title"
              };            
     
Which similarly to props can be easily accessed from inside the component: 

            <h3>{this.state.time} - {this.state.title}</h3>
      
The complete class code:

            class Event extends Component {
                state = {
                  time: "10:00",
                  title: "My state name"
                };
                render() {
                  return (
                    <React.Fragment>
                      <h3>{this.state.time} - {this.state.title}</h3>
                      <button>Change my title</button>
                    </React.Fragment>
                  );
                }
              }              
      
Preview:



2. State vs standard variable


Those of you which are familiar with other libraries, frameworks or TypeScript could ask — can't we use a normal variable? Yes — we can. We can declare and assign variables in a constructor:

            class Event extends Component {
                state = {
                  time: "10:00",
                  title: "My state title"
                };
                constructor() {
                  super();
                  this.vatTime = "12:00";
                  this.varTitle = "My variable title";
                }              
      
And in a similar way to state: 

            <React.Fragment>
                    <h3>
                      State:
                      {this.state.time} - {this.state.title}
                    </h3>
                    <h3>
                      Variable:
                      {this.vatTime} - {this.varTitle}
                    </h3>
                    <button>Change my title</button>
                  </React.Fragment>            
    
However there is one very important difference between working on variables and state in ReactState variables are meant to trigger a re-render (if they are updated in a proper way). In other words - every time you update a state variable React will automatically re-render our component view.

3. Using setState()


 Let's quickly test it — we will add two buttons to each heading - when we click on one of them it will update our title with a new value.

            render() {
                return (
                  <React.Fragment>
                    {/* This is genarated from state */}
                    <h3>
                      State:
                      {this.state.time} - {this.state.title}
                      <button
                        onClick={() => {
                          this.state.title = "My NEW state title";
                          console.log(this.state.title);
                        }}
                      >
                        Change state title
                      </button>
                    </h3>
                    {/* This is genarated from variable (constructor)  */}
                    <h3>
                      Variable:
                      {this.vatTime} - {this.varTitle}
                      <button
                        onClick={() => {
                          this.varTitle = "My NEW variable title";
                          console.log(this.varTitle);
                        }}
                      >
                        Change variable title
                      </button>
                    </h3>
                  </React.Fragment>
                );
              }            
     
And test it:



Oops! Apparently, none of the above solution works. As I mentioned before, the update of the varTitle variable doesn't trigger an update in DOM. But according to what I said — whenever we update a state variable React should re-render component in DOM. As we can see in console both variables are actually getting updated to the new value but the change isn't reflected in a browser. So why it didn't work? 

If you look closer to console you will see a warning: 



This is important to remember. You should never update state directly, instead use the dedicated for that purpose setState() function. Otherwise, React won't detect the change and update the DOM. Let's update our state variable in the proper way:

            render() {
                return (
                  <React.Fragment>
                    {/* This is genarated from state */}
                    <h3>
                      State:
                      {this.state.time} - {this.state.title}
                      <button
                        onClick={() => {
                          this.setState({ title: "Me NEW state title" });
                          console.log(this.state.title);
                        }}
                      >
                        Change state title
                      </button>
                    </h3>
                  </React.Fragment>
                );
              }              
     
Preview:




4. Asynchronous request


Now our view is getting updated. However, there is one more important thing to remember. Look closer at the value printed in the console. Although our view gets updated, the console log still shows us... the old value. But when we click for the second time it shows correct value so why it doesn't show it in the first function call? 

When you called setState() function (you told React to re-render) you have made an asynchronous request for update. You may be expecting it to do it straight away by checking state in the next line and then assuming no update has occurred because you did not see it change. This is something that never happens in JavaScript let alone React; the response to an async request never occurs until the current script has completed (even if the async action actually occurs before the current script completes!). As with all async updates, you have to wait for an event that is fired when the update occurs. In React, that event is one of the life cycle methods and we will learn about that in a separate lesson. For now, just keep in mind that although usually update happens really fast in certain cases it may get delayed

5. Combining state & props


Let's now come back to our original issue. How can we edit data which were passed from outside the component since we cannot update props? That's very simple, we will use both! States and props: 

            constructor(props) {
                super(props);
                this.state = {
                  time: this.props.time,
                  title: this.props.title
                };
              }            
      
And the entire class:

            render() {
                return (
                  <React.Fragment>
                    <h3>
                      {this.state.time} - {this.state.title}
                      <button
                        onClick={() => {
                          this.setState({ title: "Me NEW state title" });
                          console.log(this.state.title);
                        }}
                      >
                        Change state title
                      </button>
                    </h3>
                  </React.Fragment>
                );
              }
            }            
      
This allows us to set the initial value of the state to the one passed via props, and edit it later using setState()



6. Two ways to initialize variables in React


Before we move to the next lesson, I want you to keep in mind one thing. You might noticed that along the lesson I have assigned state{} in two different ways, directly in a class:

            class Event extends Component {
                state = {
                  time: "10:00",
                  title: "My state title"
                };              
      
as well as in the constructor() 

            class Event extends Component {
                constructor(props) {
                  super(props);
                  this.state = {
                    time: this.props.time,
                    title: this.props.title
                  };
                }              
     
Are they different?
They are roughly equivalent. The first approach uses the class fields proposal. It is not a part of the ECMAScript standard yet. You can think of it as an experimental feature. It most probably will work and become a standard soon but be aware that the second approach, although a bit longer is currently a recommended one. 

7. Summary 


Let's summarize the main differences between React State and Props. 

State is referred to the local state of the component which cannot be accessed and modified outside of the component and only can be used & modified inside the component.

Props, on the other hand, make components reusable by giving components the ability to receive data from the parent component in the form of props.


8. Cleanup


Since we won't edit our Schedule items yet, let's remove our state code and clean everything up: 

            class Event extends Component {
                render() {
                  return (
                    <React.Fragment>
                      <h3>
                        {this.props.time} - {this.props.title}
                      </h3>
                    </React.Fragment>
                  );
                }
              }              
      

Rate this lesson

Previous lesson Next lesson

Spread the word:
Do you need help? Use our support forum

About the author

Dawid Adach
For more than 5 years Dawid worked as an IT Consultant specializing in SOA/EAI/ESB in the banking domain. He gained experience working in countries like Netherlands, Belgium, Poland and India developing enterprise-class systems for the most prestigious companies. Since co-founding mdbootstrap.com & brandflow.net in 2016 he has been using and teaching technologies such as Angular, TypeScript, PHP, AJAX, Mongo, SQL, Hadoop Stack, Virtualization, Automation and many others...