This post is part of the series 30 Days of React.

In this series, we're starting from the very basics and walk through everything you need to know to get started with React. If you've ever wanted to learn React, this is the place to start!

State

Edit this page on Github

Today we're getting started on how stateful components work in React and look at when and why we'll use state.

We've almost made it through your first week of getting up and running on React. We have worked through JSX, building our first components, setting up parent-child relationships, and driving our component properties with React. We have one more major idea we have yet to discuss about React, the idea of state.

The state of things

React does not allow us to modify this.props on our components for good reason. Imagine if we passed in the title prop to the Header component and the Header component was able to modify it. How do we know what the title is of the Header component? We set ourselves up for race-conditions, confusing data state, and it would be an all-around bad idea to modify a variable passed to us by a parent component and modified in a child.

However, sometimes a component needs to be able to update it's own state. For example, setting an active flag or updating a timer on a stopwatch, for instance.

While it's preferable to use props as much as we can, sometimes we need to hold on to the state of a component. To handle this, React gives us the ability to have state in our components.

state in a component is intended to be completely internal to the Component and it's children (i.e. accessed by the component and any children it used). Similar to how we access props in a component, the state can be accessed via this.state in a component. Whenever the state changes (via the this.setState() function), the component will rerender.

For instance, let's say we have a simple clock component that shows the current time:

Even though this is a simple clock component, it does retain state in that it needs to know what the current time is to display. Without using state, we could set a timer and rerender the entire React component, but other components on the page may not need rerendering... this would be a headache.

Instead, we can set a timer to call rerender inside the component and change the internal state of this component.

Let's take a stab at building this component. First, we'll create the component we'll call Clock. Before we get into the state, let's build the component and create the render() function. We'll need to take into account the number and prepend a zero (0) to the number if the numbers are smaller than 10 and set the am/pm appropriately. The end result of the render() function might look something like this:

class Clock extends React.Component {
  render() {
    const currentTime = new Date(),
          hours = currentTime.getHours(),
          minutes = currentTime.getMinutes(),
          seconds = currentTime.getSeconds(),
          ampm = hours >= 12 ? 'pm' : 'am';

    return (
      <div className="clock">
        {
          hours == 0 ? 12 :
            (hours > 12) ?
              hours - 12 : hours
        }:{
          minutes > 9 ? minutes : `0${minutes}`
        }:{
          seconds > 9 ? seconds : `0${seconds}`
        } {ampm}
      </div>
    )
  }
}
// ...
export default Clock

If we render our new Clock component, we will only get a time rendered everytime the component itself rerenders. It's not a very useful clock (yet). In order to convert our static time display Clock component into a clock that displays the time, we'll need to update the time every second.

In order to do that, we'll need to track the current time in the state of the component. To do this, we'll need to set an initial state value. In the ES6 class style, we can set the initial state of the component in the constructor() by setting this.state to a value.

  constructor(props) {
    super(props);
    this.state = this.getTime();
  }

The first line of the constructor should always call super(props). If you forget this, the component won't like you very much (i.e. there will be errors).

Now that we have a this.state defined in our Clock component, we can reference it in the render() function using the this.state. Let's update our render() function to grab the values from this.state:

class Clock extends React.Component {
  // ...
  render() {
    const {hours, minutes, seconds, ampm} = this.state;
    return (
      <div className="clock">
        {
          hours === 0 ? 12 :
            (hours > 12) ?
              hours - 12 : hours
        }:{
          minutes > 9 ? minutes : `0${minutes}`
        }:{
          seconds > 9 ? seconds : `0${seconds}`
        } {ampm}
      </div>
    )
  }
}

Instead of working directly with data values, we can now update the state of the component. In order to update the state, we'll use the function this.setState(), which will trigger the component to rerender.

In our Clock component, let's use the native setTimeout() JavaScript function to create a timer to update the this.state object in 1000 milliseconds. We'll place this functionality in a function as we'll want to call this again.

class Clock extends React.Component {
  // ...
  constructor(props) {
    super(props);
    this.state = this.getTime();
  }
  // ...
  setTimer() {
    clearTimeout(this.timeout);
    this.timeout = setTimeout(this.updateClock.bind(this), 1000);
  }
  // ...
  updateClock() {
    this.setState(this.getTime, this.setTimer);
  }
  // ...
}

We will get into the lifecycle hooks in the next section, but for the time being we'll call this in the constructor() for simplicity.

In the updateClock() function we'll want to update the state with the new time. We can now update the state in the updateClock() function:

class Clock extends React.Component {
  // ...
  updateClock() {
    this.setState(this.getTime, this.setTimer);
  }
  // ...
}

The component will be mounted on the page and in (approximately) one second (1000 milliseconds) it updates the current time. However, it won't be reset again. We can simply call the setTimer() function again at the end of the function:

class Clock extends React.Component {
  // ...
  updateClock() {
    const currentTime = new Date();
    this.setState({
      currentTime: currentTime
    })
    this.setTimer();
  }
  // ...
}

Now the component itself might rerender slower than the timeout function gets called again, which would cause a rerendering bottleneck and needlessly using up precious battery on mobile devices. Instead of calling the setTimer() function after we call this.setState(), we can pass a second argument to the this.setState() function which will be guaranteed to be called after the state has been updated.

class Clock extends React.Component {
  // ...
  updateClock() {
    const currentTime = new Date();
    this.setState({
      currentTime: currentTime
    }, this.setTimer);
  }
  // ...
}

Update our activity list

We can update our Header component in our activity list we've been working on through the last section. When the user clicks on the search icon () in the corner, we'll want to show the <input /> component.

Try it! Click on the search icon below:

Knowing what we know now with this.state, we can now update the view to add a conditional rendering of the <input />:

class Header extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      searchVisible: false
    }
  }

  // toggle visibility when run on the state
  showSearch() {
    this.setState({
      searchVisible: !this.state.searchVisible
    })
  }

  render() {
    // Classes to add to the <input /> element
    let searchInputClasses = ["searchInput"];

    // Update the class array if the state is visible
    if (this.state.searchVisible) {
      searchInputClasses.push("active");
    }

    return (
      <div className="header">
        <MenuButton />

        <span className="title">
          {this.props.title}
        </span>

        <input
          type="text"
          className={searchInputClasses.join(' ')}
          placeholder="Search ..." />

        {/* Adding an onClick handler to call the showSearch button */}
        <div
          onClick={this.showSearch.bind(this)}
          className="fa fa-search searchIcon"></div>
      </div>
    )
  }
}

Some things to keep in mind

  • When we call this.setState() with an object argument, it will perform a shallow merge of the data into the object available via this.state and then will rerender the component.

  • We generally only want to keep values in our state that we'll use in the render() function. From the example above with our clock, notice that we stored the hours, minutes, and seconds in our state. It's usually a bad idea to store objects or calculations in the state that we don't plan on using in the render function as it can cause unnecessary rendering and wasteful CPU cycles.

As we noted at the top of this section, it's preferred to use props when available not only for performance reasons, but because stateful components are more difficult to test.

Today we've updated our components to be stateful and now have a handle on how to make a component stateful when necessary. Tomorrow we'll dive into the lifecycle of a component and when/how to interact with the page.

The <MenuButton /> component referenced above is in the code repository and just presents a nice display for the menu button.

const MenuButton = (props) => (
  <div className="menuIcon">
    <div className="dashTop"></div>
    <div className="dashBottom"></div>
    <div className="circle"></div>
  </div>
)

Ari Lerner

Hi, I'm Ari. I'm an author of Fullstack React and ng-book and I've been teaching Web Development for a long time. I like to speak at conferences and eat spicy food. I technically got paid while I traveled the country as a professional comedian, but have come to terms with the fact that I am not funny.

Connect with Ari on Twitter at @auser.