Manipulating State in React.js

August 11, 2014
Development, Footer

In the previous entry of this series we looked at how React components encapsulated browser events and transformed them into component-level events. In this post we'll look at how those events impact the state of an application.

Creating TodoStore to hold state

Our Todo application is capturing an 'add' event, the next step is adding a todo. In order to do so, we need to backpedal and display a list of todos backed by a simple store. This store is intentionally naive for illustrative purposes.

Let's start with the simple, singleton store:

var TodoStore = {

  todos: [],

  addTodo: function(todo) {
    this.todos.push(todo);
  }

};

Our TodoStore maintains an array of todos (strings). Its single method appends a new todo to the array.

Setting up the TodoList component

Before we pull in the state, lets create a simple component for displaying the todos.

/** @jsx React.DOM */
var TodoList = React.createClass({
  propTypes: {
    todos: React.PropTypes.array.isRequired
  },
  render: function() {
    var todos     = this.props.todos,
        listItems = [];
    for (var key in todos) {
      listItems.push(<li key={key}>{todos[key]}</li>);
    }
    return <ul>{listItems}</ul>;
  }
});

If you're working with React, this is simple list component boilerplate, nothing major of note.

Pulling and manipulating state

Ideally, state is introduced to React at the top-level component. In our case, it's the TodoApp component. We'll setup React's getInitialState method and pass the app's state into the TodoList component from above.

/** @jsx React.DOM */
var TodoApp = React.createClass({
  getInitialState: function() { return TodoStore; }
  render: function() {
    return (
      <div>
        <h1>Todos</h1>
        <TodoAdder onAdd={this._handleAdd} />
        <TodoList todos={this.state.todos} />
      </div>
    );
  },
  _handleAdd: function(todo) {
    TodoStore.addTodo(todo);
    return this.setState(TodoStore);
  }
});

Three notable things are happening here:

First, we're setting up the app component's initial state by implementing getInitialState. This method is called as the component is mounting and simply assigns TodoStore as the state. In a full-fledged Store implementation, like demonstrated in Flux, state may be extracted from the store rather than referencing the store directly. TodoApp's this.state is now the TodoStore.

Second, we're passing the state into a child component via a prop. This is a common pattern in React. Props are immutable. This makes components simpler to reason about: only state is mutable and state tends to only exist at the top of the component tree.

Finally, in the _handleAdd event handler we setup in part 1, we're now adding the new todo to the store. Calling the component's setState method indicates to react that a mutation has been made and that it's time for the UI to redraw.

Currently, if you were to add a new Todo to the store through the console it wouldn't show up. Calling setState directly, in this fashion, is a tightly coupled anti-pattern we'll fix in the final part of this series with evented indirection. Stay tuned for part 3!

Comments

Eduardo's avatar
Eduardo
Great article.
Paul Pucciarelli's avatar
Paul Pucciarelli
Found this organically via google. Nice article ; P
wouter's avatar
wouter
great article - but where is the rest?
Looking forward to Part 3. SO > When will it be there?????????

Thanks - Wouter
Gina Bultman's avatar
Gina Bultman
Manipulating State in React.js is awesome

Leave a comment