Manipulating State in React.js
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
Great article.Paul Pucciarelli
Found this organically via google. Nice article ; Pwouter
great article - but where is the rest?Looking forward to Part 3. SO > When will it be there?????????
Thanks - Wouter
Gina Bultman
Manipulating State in React.js is awesomeLeave a comment