Components have two associated bits of data. The first is props, which we’ve already seen. Props are passed down from the parent and we can’t change them inside our components.

The other important bit of data our components have is state. Unlike props, you can change the state of the component and each time you do, the component will be rendered again to show the changes.

Let’s design a new component. We’ll make a timer that counts up from 0 in seconds and resets to 0 it is clicked. We could manage time somewhere else and re-render the component with new props, every second. Or we could let the component manage itself, which makes a lot more sense.

var Timer = React.createClass({
  render: function() {
    return (
      <button>{this.state.time} s</button>
    );
  }
});

As you can see, when we are telling a component how it should render, we use state in a very similar way to props. Now that we’ve told our timer how to render, now we need to tell it how to behave. Somewhere we need to update the state once a second.

Lifecycle Hooks

React gives us a number of other methods, other than render, that will all be called at certain times in a components life. For now, we are only interested in two of them: getInitialState and componentDidMount. Don’t worry about the slightly weird names, they’ll make sense eventually.

Let’s add the getIntitialState method to our timer component.

var Timer = React.createClass({
  getInitialState: function() {
    return {
      time: 0
    };
  },
  render: function() {
    return (
      <button>{this.state.time} s</button>
    );
  }
});

This method simply returns whatever this.state should be set to when we render the component for the first time. Our timer is going to count up from 0, so setting this.state.time to 0 is what we want to do here. Fairly straightforward.

Next we want to use setInterval to update the this.state.time each second. We only want to start updating our state when we know our component has successfully ended up in the DOM. React lets us know when this has happened by calling the componentDidMount method.

Add the following componentDidMount method to the Timer component.

var Timer = React.createClass({
  getInitialState: function() {
    return {
      time: 0
    };
  },
  componentDidMount: function() {
    setInterval(function() {
      this.setState({ time: this.state.time + 1 });
    }.bind(this), 1000);
  },
  render: function() {
    return (
      <button>{this.state.time} s</button>
    );
  }
});

Don’t worry about the .bind(this), that’s a quirk of the way setInterval handles this, not something that’s related to React.

Now we’re starting to get something that looks and feels like a proper component. It’s important to notice that we didn’t do

setInterval(function() {
  this.state.time += 1;
}, 1000);

It’s essential that we call this.setState because that lets React know that it needs to re-render the component.

Open the app in the browser and you should see the time counting up.

Finally, we want to reset the timer if the button is clicked. This involves setting this.state.time back to 0 and we need it to happen whenever the button is clicked.

React lets us define our own custom methods for our components. Let’s create one called resetTimer.

var Timer = React.createClass({
  resetTimer: function() {
    this.setState({ time: 0 });
  },
  getInitialState: function() {
    return {
      time: 0
    };
  },
  componentDidMount: function() {
    setInterval(function() {
      this.setState({ time: this.state.time + 1 });
    }.bind(this), 1000);
  },
  render: function() {
    return (
      <button>{this.state.time} s</button>
    );
  }
});

Finally, we need to make sure it actually gets called. We can add event listeners to our React components in a similar way to inline HTML elements event listeners.

return (
  <button onClick={this.resetTimer}>{this.state.time} s</button>
);

For a long time, the teaching has been that we should keep our event code free from our HTML, because it becomes difficult to work out what is calling what and where events are being fired from.

However, React components force all the behaviour to be closely tied together in small, reusable components. It’s always easy to find the function that an onClick handler points to, because it also lives within the component!.

With the event handler added, the button should count up and reset when you click it.

Make sure it works, then it’s time for the next step..