Extracting Container Components

by acdlite

HTML

<script src="https://npmcdn.com/redux/dist/redux.js"></script>
<script src="https://npmcdn.com/expect/umd/expect.js"></script>
<script src="https://wzrd.in/standalone/deep-freeze@latest"></script>
<script src="https://npmcdn.com/[email protected]/dist/react.js"></script>
<script src="https://npmcdn.com/[email protected]/dist/react-dom.js"></script>
<script src="https://npmcdn.com/[email protected]/dist/react-redux.js"></script>
<div id="root"></div>

Babel + JSX

/* Now we will introduct React Redux's `connect()`
 * 
 * Also, rather than using a single subscription at the root of the app,
 * we will use multiple subscriptions, using container components.
 *
 * - Divide FilterLink into Link and subscribed FilterLink.
 * - Extract VisibleTodoList and remove top-level subscription.
 */

const todo = (state, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return {
        id: action.id,
        text: action.text,
        completed: false
      };
    case 'TOGGLE_TODO':
      if (state.id !== action.id) {
        return state;
      }

      return {
        ...state,
        completed: !state.completed
      };
    default:
      return state;
  }
};


const todos = (state = [], action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        todo(undefined, action)
      ];
    case 'TOGGLE_TODO':
      return state.map(t => todo(t, action));
    default:
      return state;
  }
};

const visibilityFilter = (
  state = 'SHOW_ALL',
  action
) => {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter;
    default:
      return state;
  }
};

const { combineReducers } = Redux;

const todoApp = combineReducers({
  todos,
  visibilityFilter
});

const { createStore } = Redux;
const store = createStore(todoApp);

const { Component } = React;

const FilterLink = ({
  filter,
  currentFilter,
  children
}) => {
  if (filter === currentFilter) {
    return <span>{children}</span>;
  }

  return (
    <a href='#'
       onClick={e => {
         e.preventDefault();
         store.dispatch({
           type: 'SET_VISIBILITY_FILTER',
           filter
         });
       }}
    >
      {children}
    </a>
  );
};

const getVisibleTodos = (
  todos,
  filter
) => {
  switch (filter) {
    case 'SHOW_ALL':
      return todos;
    case 'SHOW_COMPLETED':
      return todos.filter(
        t => t.completed
      );
    case 'SHOW_ACTIVE':
      return...