[Redux] React Todo List Example (Filtering Todos)

/**
 * A reducer for a single todo
 * @param state
 * @param action
 * @returns {*}
 */
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;
    }
};

/**
 * The reducer for the todos
 * @param state
 * @param action
 * @returns {*}
 */
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;

    }
};

/**
 * Reducer for the visibilityFilter
 * @param state
 * @param action
 * @returns {*}
 */
const visibilityFilter = ( state = 'SHOW_ALL',
                           action ) => {
    switch ( action.type ) {
        case 'SET_VISIBILITY_FILTER':
            return action.filter;
        default:
            return state;
    }
};


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

/**
 * combineReducers: used for merge reducers togethger
 * createStore: create a redux store
 */
const { combineReducers, createStore } = Redux;
const todoApp = combineReducers( {
    todos,
    visibilityFilter
} );

const store = createStore( todoApp );

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>
  );
};

/**
 * For generate todo's id
 * @type {number}
 */
let nextTodoId = 0;

/**
 * React related
 */
const {Component} = React;
class TodoApp extends Component {
    render() {
      
      const {todos, visibilityFilter} = this.props;
      let visibleTodos = getVisibleTodos(todos, visibilityFilter);
      
        return (
            <div>
                <input ref={
        (node)=>{
            this.input = node
        }
    }/>
                <button onClick={
        ()=>{
        //After clicking the button, dispatch a add todo action
            store.dispatch({
                type: 'ADD_TODO',
                id: nextTodoId++,
                text: this.input.value
            })
            this.input.value = "";
        }
    }>ADD todo
                </button>
                <ul>
                    {visibleTodos.map( ( todo )=> {
                        return (
                            <li key={todo.id}
                                style={{
                                 textDecoration: todo.completed ?
                                 'line-through' : 'none'
                                }}

                                onClick={ ()=>{
                                   store.dispatch({
                                   type: 'TOGGLE_TODO',
                                   id: todo.id
                                  })
                                }}
                            >
                                {todo.text}
                            </li>
                        )
                    } )}
                </ul>
                <p>
                  Show:
                  {' '}
                  <FilterLink filter="SHOW_ALL" currentFilter={visibilityFilter}>
                    All
                  </FilterLink>
                  {' '}
                  <FilterLink filter="SHOW_ACTIVE" currentFilter={visibilityFilter}>
                    Active
                  </FilterLink>
                  {' '}
                  <FilterLink filter="SHOW_COMPLETED" currentFilter={visibilityFilter}>
                    Completed
                  </FilterLink>
                  {' '}
                </p>
            </div>
        );
    }
}

const render = () => {
    ReactDOM.render(
        <TodoApp {...store.getState()}/>,
        document.getElementById( 'root' )
    );
};

//Every time, store updated, also fire the render() function
store.subscribe( render );
render();
原文地址:https://www.cnblogs.com/Answer1215/p/5133697.html