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();
  • 相关阅读:
    Struts2声明式异常处理
    几种常用的过滤器
    Jdk 和 Tomcat的 安装。(旧版本,请看新版本3篇)
    java 判断字符串是否相等
    PreparedStatement 查询 In 语句 setArray 等介绍。
    String、StringBuffer与StringBuilder之间区别
    IntelliJ IDEA 里 查看一个函数注释的方法是 ctrl+q
    Java字符串拼接效率对比
    Java 中判断字符串是否为空
    IntelliJ IDEA + Tomcat ;On Upate Action 与 On Frame Deactivation
  • 原文地址:https://www.cnblogs.com/Answer1215/p/5164305.html
Copyright © 2011-2022 走看看