redux/todomvc refactor

We can easily refactor all sub-render calls into separate stateless components, wrap them inside a pure HoC and increase testability and performance. We can wrap the MainSection component in a pure HoC on export.

  • Separate components is better for testing
import pure from 'recompose/pure';
export const ToggleAll = (props) => {
  const { todos, actions, completedCount } = props;
  if (todos.length > 0) {
    return (
      <input className="toggle-all"
             type="checkbox"
             checked={completedCount === todos.length}
             onChange={actions.completeAll}/>
    );
  }
  return <div></div>;
}
const PureToggleAll = pure(ToggleAll);
export default PureToggleAll;
import pure from 'recompose/pure';
import Footer from './Footer';
export const ShowFooter = (props) => {
  const { todos, completedCount, filter, handleShow, actions } = props;
  const activeCount = todos.length - completedCount;

  const handleClearCompleted = () => {
    const atLeastOneCompleted = todos.some(todo => todo.completed);
    if (atLeastOneCompleted) {
      actions.clearCompleted();
    }
  }

  if (todos.length) {
    return (
      <Footer completedCount={completedCount}
              activeCount={activeCount}
              filter={filter}
              onClearCompleted={handleClearCompleted}
              onShow={handleShow}
              />
    );
  }
  return <div></div>;
}
const PureShowFooter = pure(ShowFooter);
export default PureShowFooter;
render() {
  const { todos, actions } = this.props;
  const { filter } = this.state;

  const filteredTodos = todos.filter(TODO_FILTERS[filter]);
  const completedCount = todos.reduce((count, todo) =>
    todo.completed ? count + 1 : count,
    0
  );

  return (
    <section className="main">
      <ToggleAll
        completedCount={completedCount}
        todos={todos}
        actions={actions}
      />
      <ul className="todo-list">
        {filteredTodos.map(todo =>
          <TodoItem key={todo.id} todo={todo} {...actions} />
        )}
      </ul>
      <ShowFooter
        completedCount={completedCount}
        todos={todos}
        filter={filter}
        handleShow={this.handleShow.bind(this)}
        actions={actions}
      />
    </section>
  );
}