Summary

A to do application is a common project for learning React. React is a JS library which helps build efficient and fast UIs. React is component based, and every component has the ability to manage its own state. Each component is written in JS, which allows the ability to pass data throughout the application without changing anything in the DOM.
There were two phases of the To-Do project:

  1. Phase 1: Build react components which could manage state and store data in local storage
  2. Phase 2: Implement Redux, a state container which comes with some really cool tools

My favorite aspect of React is that you can separate parts of your application into components. These components allow you to split your UI into separate reusable pieces. You can render a component which itself renders subcomponents.
You simply need to include the main component in your application file, and have it render into the DOM element you are targeting on the HTML file.

Phase 1

Container Component

In the application, I needed to have a search bar, a visual list of the to-do items, and a place to type in new tasks. Each of these would be their own component, but they need to be held within one container component. My main component, TodoApp.jsx was setup in this format:

TodoApp.jsx:

var React = require('react');
var TodoApp = React.createClass({
  render: function() {
    return (
      <div>
        <p>Other components will be in this area!</p>
      </div>
    );
  }
});
module.exports = TodoApp; 

The module.exports = TodoApp; allows you to inject this component into other files in your application. The main JS file in my app, app.jsx is setup in this fashion:
app.jsx:

var TodoApp = require('TodoApp');
ReactDOM.render(
  <TodoApp/>,
  document.getElementById('app')
);

The first line of code directly above includes the component into this completely separate file. The remainder of the code is required to render the TodoApp into the DOM element with the ID of ‘app’.

Eventually, the TodoApp.jsx file looks like this to include the subcomponents needed to accomplish the tasks.

var React = require('react');
var TodoApp = React.createClass({
  render: function() {
    return (
      <div>
        <TodoSearch onSearch={this.handleSearch}/>
        <TodoList todos={filteredTodos} onToggle={this.handleToggle}/>
        <AddTodo onNewTodo={this.handleAddTodo}/>
      </div>
    );
  }
});
module.exports = TodoApp; 

Within the subcomponents, events such as “onSearch” take place. When those functions are triggered, they have access to functions in TodoApp through the props…

Props

Props (Properties) have the ability to pass data between components. In the code above, handleSearch, handleToggle, and handleAddTodo are all functions within the TodoApp, the container component. This container component interacts with its child components through props.
In the AddTodo component, when a user triggers the onNewTodo function, it will call the TodoApp component function of handleAddTodo. The child components will trigger changes in the parent/container component, which changes the state of the application.

State

In my application, when a user onNewTodo, it triggers the parent component’s handleAddTodo. This will change the state of the application
AddTodo.jsx: call:

this.props.onNewTodo(todoText)

Triggers:

<AddTodo onNewTodo={this.handleAddTodo}/>

Within TodoApp.jsx:

handleAddTodo: function(text) {
this.setState({
  todos: [
    ...this.state.todos, 
    {
      id: uuid(),
      text: text,
      completed: false,
      createdAt: moment().unix(),
      completedAt: undefined,
    }
  ],
})

Above, we call this.setState() to change the state of the application. There are a variety of Lifecycle Methods that are available with React to help you manage state at different points.

    Here are a few I used frequently in this app:
  • componentWillUpdate()
  • componentDidUpdate()
  • setState()
  • getState()

There are many more that are available in the link directly above

Local Storage

At this point my components all work well together. When something happens in a component, it is passed up through the parent and back down to all of the children with the render functions. The problem is when you refresh the page all of your To-Do tasks will disappear. As a temporary solution I set up an API tool which saved the tasks to a browser’s local storage.
TodoApp.jsx:

componentDidUpdate: function() {
  TodoAPI.setTodos(this.state.todos);
}

TodoAPI.jsx:

setTodos: function(todos) {
  if ($.isArray(todos)) {
    localStorage.setItem('todos', JSON.stringify(todos));
    return todos;
  }
},

The code directly above sets the todos into local storage
Similar functions in the TodoAPI can filter todos for search-text or completion status, as well as get the stored todos to display in the application.

Phase 2: Implement Redux

Redux simplifies the state of the application by storing the entire state in a single store. To change the state tree, you need to trigger an action. To specify what that action does to the state tree, you use reducers.

I will explain how I implemented those three core redux building blocks below…