React Todo List Example (Filtering Todos)

In notebook:
Egghead Redux
Created at:
2016-07-09
Updated:
2016-07-09
Tags:
libraries React JavaScript pattern
Will dispatch the SET_VISIBILITY_FILTER action. 
  const { Component } = React;

// ++++ crate FilterLink React component
const FilterLink = ({filter, children}) => {
  return <a href="#" onClick = {e => {
    e.preventDefault();
    store.dispatch({
      type: 'SET_VISIBILITY_FILTER',
      filter
    });
  }}>
    {children}
  </a>
}


let nextTodoId = 0;
class TodoApp extends Component {
  render() {
    // ++++ get the visible todos
    const visibleTodos = getVisibleTodos(
      this.props.todos,
      this.props.visibilityFilter
    )
    return (
      <div>
        <input .../>
        <button onClick={() => {...}</button>
        <ul>
        // ++-- change here to visible todos
          // {this.props.todos.map(todo => {...}
          {visibleTodos.todos.map(todo => {...}
        </ul>
        // ++++
        <p>
          Show: 
          {' '}
          <FilterLink filter='SHOW_ALL'>All</FilterLink>
          {' '}
          <FilterLink filter='SHOW_ACTIVE'>Active</FilterLink>
          {' '}
          <FilterLink filter='SHOW_COMPLETED'>Completed</FilterLink>
          {' '}
        </p>
      </div>  
    )
  }
}

// ++++ add todo filter function
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
      )
  }
}


const render = () => {
  ReactDOM.render(
  // ++-- pass all state fields to the rendering
    <TodoApp {...store.getState()} />,
    document.getElementById('root');
    )  
};

store.subscribe(render);
render();
Next step: highlight the chosen (active) visibility link selector in the UI
  const { Component } = React;

// ++++ add currentFilter argument
const FilterLink = ({filter, currentFilter, children}) => {
  // ++++
  if (filter === currentFilter) {
    // return a span instead of a link (selected vfilter)
    return <span>{children}</span>;
  }
  
  return <a href="#" onClick = {e => {
    e.preventDefault();
    store.dispatch({
      type: 'SET_VISIBILITY_FILTER',
      filter
    });
  }}>
    {children}
  </a>
}


let nextTodoId = 0;
class TodoApp extends Component {
  render() {
    // ++++ destructuring
    const {
      todos,
      visibilityFilter
    } = this.props;
    
    
    
    const visibleTodos = getVisibleTodos(
      // ++-- thanks to destructuring
      // we can access them directly
      todos,
      visibilityFilter
    )
    return (
      <div>
        <input .../>
        <button onClick={() => {...}</button>
        <ul>
          {visibleTodos.todos.map(todo => {...}
        </ul>
        <p>
          Show: 
          {' '}
          // add currentFilter to each FilterLink
          <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 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
      )
  }
}


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

store.subscribe(render);
render();