zoukankan      html  css  js  c++  java
  • [Redux] Extracting Presentational Components -- Footer, FilterLink

    Code to be refactored: 

    let nextTodoId = 0;
    class TodoApp extends Component {
      render() {
        const {
          todos,
          visibilityFilter
        } = this.props;
        const visibleTodos = getVisibleTodos(
          todos,
          visibilityFilter
        );
        return (
          <div>
            <input ref={node => {
              this.input = node;
            }} />
            <button onClick={() => {
              store.dispatch({
                type: 'ADD_TODO',
                text: this.input.value,
                id: nextTodoId++
              });
              this.input.value = '';
            }}>
              Add Todo
            </button>
            <ul>
              {visibleTodos.map(todo =>
                <li key={todo.id}
                    onClick={() => {
                      store.dispatch({
                        type: 'TOGGLE_TODO',
                        id: todo.id
                      });         
                    }}
                    style={{
                      textDecoration:
                        todo.completed ?
                          'line-through' :
                          'none'
                    }}>
                  {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 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>
      );
    };

    Refactor footer part into a functional component, which contains all these three filter links. Pass in visibilityFilter as props:

    const Footer = ({
      visibilityFilter
    }) => (
      <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>
    );

    In the FilterLink,  we want it to be presentational components. However, the filter link includes a short dispatch call. I am replacing it with an on click call. I pass the filter as the single parameter for the calling component's convenience. I add on click to the props.

    const FilterLink = ({
      filter,
      currentFilter,
      children,
      onFilterClick
    }) => {
      if (filter === currentFilter) {
        return <span>{children}</span>;
      }
    
      return (
        <a href='#'
           onClick={e => {
             e.preventDefault();
             onFilterClick(filter);
           }}
        >
          {children}
        </a>
      );
    };
    const Footer = ({
      visibilityFilter,
      onFilterClick
    }) => (
      <p>
              Show:
              {' '}
              <FilterLink
                filter='SHOW_ALL'
                currentFilter={visibilityFilter}
                onFilterClick={onFilterClick}
              >
                All
              </FilterLink>
              {', '}
              <FilterLink
                filter='SHOW_ACTIVE'
                currentFilter={visibilityFilter}
                onFilterClick={onFilterClick}
              >
                Active
              </FilterLink>
              {', '}
              <FilterLink
                filter='SHOW_COMPLETED'
                currentFilter={visibilityFilter}
                onFilterClick={onFilterClick} 
              >
                Completed
              </FilterLink>
            </p>
    );

      -----------------------------------

    Code:

    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;
    
    
    /**
     Functional compoment, persental compoment: doesn't need to know what to do, just show the interface, call the callback function.
    */
    const AddTodo = ({
      onAddTodo
    }) => {
      
      let input;
      return (
         <div>
              <input ref={node => {
              input = node;
            }} />
            <button onClick={() => {
              onAddTodo(input.value);
              input.value = '';
            }}>
              Add Todo
            </button>
         </div>
      );
    }
    
    /* Functional component */
    const Footer = ({
      visibilityFilter,
      onFilterClick
    }) => (
            <p>
              Show:
              {' '}
              <FilterLink
                filter='SHOW_ALL'
                currentFilter={visibilityFilter}
                onFilterClick={onFilterClick}
              >
                All
              </FilterLink>
              {', '}
              <FilterLink
                filter='SHOW_ACTIVE'
                currentFilter={visibilityFilter}
                onFilterClick={onFilterClick}
              >
                Active
              </FilterLink>
              {', '}
              <FilterLink
                filter='SHOW_COMPLETED'
                currentFilter={visibilityFilter}
                onFilterClick={onFilterClick}
              >
                Completed
              </FilterLink>
            </p>
    );
    
    const FilterLink = ({
      filter,
      currentFilter,
      children,
      onFilterClick
    }) => {
      if (filter === currentFilter) {
        return <span>{children}</span>;
      }
    
      return (
        <a href='#'
           onClick={e => {
             e.preventDefault();
             onFilterClick(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 todos.filter(
            t => !t.completed
          );
      }
    }
    
    let nextTodoId = 0;
    class TodoApp extends Component {
      render() {
        const {
          todos,
          visibilityFilter
        } = this.props;
        const visibleTodos = getVisibleTodos(
          todos,
          visibilityFilter
        );
        return (
          <div>
            <AddTodo 
               onAddTodo={ text =>
                  store.dispatch({
                      type: 'ADD_TODO',
                      id: nextTodoId++,
                      text
                  })
               }
            />
            <ul>
              {visibleTodos.map(todo =>
                <li key={todo.id}
                    onClick={() => {
                      store.dispatch({
                        type: 'TOGGLE_TODO',
                        id: todo.id
                      });         
                    }}
                    style={{
                      textDecoration:
                        todo.completed ?
                          'line-through' :
                          'none'
                    }}>
                  {todo.text}
                </li>
              )}
            </ul>
            <Footer 
               visibilityFilter = {visibilityFilter}
               onFilterClick={ (filter) => {
                  store.dispatch({
                     type: 'SET_VISIBILITY_FILTER',
                     filter
                 });
               }}
            />
          </div>
        );
      }
    }
    
    const render = () => {
      ReactDOM.render(
        <TodoApp
          {...store.getState()}
        />,
        document.getElementById('root')
      );
    };
    
    store.subscribe(render);
    render();
  • 相关阅读:
    C#深入浅出 修饰符(二)
    HDU 5785 Interesting
    HDU 5783 Divide the Sequence
    HDU 5781 ATM Mechine
    UVA 714 Copying Books
    uva 1471 Defense Lines
    UVA 11134 Fabled Rooks
    UVA 11572 Unique Snowflakes
    UVA 11093 Just Finish it up
    UVA 10954 Add All
  • 原文地址:https://www.cnblogs.com/Answer1215/p/5164305.html
Copyright © 2011-2022 走看看