zoukankan      html  css  js  c++  java
  • [Redux] Passing the Store Down Explicitly via Props

    n the previous lessons, we used this tool to up level variable to refer to the Redux chore. The components that access this chore, such as the container components, read this straight from it, subscribe to this chore, and dispatch actions on this chore using this chore top-level variable.

    This approach works fine for JS bin example where everything is in a single file. However, it doesn't scale to real applications for several reasons.

    First of all, it makes your container components harder to test because they reference a specific chore, but you might want to supply a different marks chore in the test. Secondly, it makes it very hard to implement universal replications that are rendered on the server, because on the server, you want to supply a different chore instance for every request because different requests have different data.

    Every container component needs a reference to this chore so unfortunately, we have to pass it down to every component as a prop. It's less effort than passing different data through every component, but it's still inconvenient. So, don't worry, we'll find a better solution later, but for now, we need to see the problem.

    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 { Component } = React;
    
    const Link = ({
      active,
      children,
      onClick
    }) => {
      if (active) {
        return <span>{children}</span>;
      }
    
      return (
        <a href='#'
           onClick={e => {
             e.preventDefault();
             onClick();
           }}
        >
          {children}
        </a>
      );
    };
    
    class FilterLink extends Component {
      componentDidMount() {
        const { store } = this.props;
        this.unsubscribe = store.subscribe(() =>
          this.forceUpdate()
        );
      }
      
      componentWillUnmount() {
        this.unsubscribe();
      }
      
      render() {
        const props = this.props;
        const { store } = props;
        const state = store.getState();
        
        return (
          <Link
            active={
              props.filter ===
              state.visibilityFilter
            }
            onClick={() =>
              store.dispatch({
                type: 'SET_VISIBILITY_FILTER',
                filter: props.filter
              })
            }
          >
            {props.children}
          </Link>
        );
      }
    }
    
    const Footer = ({ store }) => (
      <p>
        Show:
        {' '}
        <FilterLink
          filter='SHOW_ALL'
          store={store}
        >
          All
        </FilterLink>
        {', '}
        <FilterLink
          filter='SHOW_ACTIVE'
          store={store}
        >
          Active
        </FilterLink>
        {', '}
        <FilterLink
          filter='SHOW_COMPLETED'
          store={store}
        >
          Completed
        </FilterLink>
      </p>
    );
    
    const Todo = ({
      onClick,
      completed,
      text
    }) => (
      <li
        onClick={onClick}
        style={{
          textDecoration:
            completed ?
              'line-through' :
              'none'
        }}
      >
        {text}
      </li>
    );
    
    const TodoList = ({
      todos,
      onTodoClick
    }) => (
      <ul>
        {todos.map(todo =>
          <Todo
            key={todo.id}
            {...todo}
            onClick={() => onTodoClick(todo.id)}
          />
        )}
      </ul>
    );
    
    let nextTodoId = 0;
    const AddTodo = ({ store }) => {
      let input;
    
      return (
        <div>
          <input ref={node => {
            input = node;
          }} />
          <button onClick={() => {
            store.dispatch({
              type: 'ADD_TODO',
              id: nextTodoId++,
              text: input.value
            })
            input.value = '';
          }}>
            Add Todo
          </button>
        </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
          );
      }
    }
    
    class VisibleTodoList extends Component {
      componentDidMount() {
        const { store } = this.props;
        this.unsubscribe = store.subscribe(() =>
          this.forceUpdate()
        );
      }
      
      componentWillUnmount() {
        this.unsubscribe();
      }
      
      render() {
        const props = this.props;
        const { store } = props;
        const state = store.getState();
        
        return (
          <TodoList
            todos={
              getVisibleTodos(
                state.todos,
                state.visibilityFilter
              )
            }
            onTodoClick={id =>
              store.dispatch({
                type: 'TOGGLE_TODO',
                id
              })            
            }
          />
        );
      }
    }
    
    const TodoApp = ({ store }) => (
      <div>
        <AddTodo store={store} />
        <VisibleTodoList store={store} />
        <Footer store={store} />
      </div>
    );
    
    
    const { createStore } = Redux;
    
    ReactDOM.render(
      <TodoApp store={createStore(todoApp)} />,
      document.getElementById('root')
    );
  • 相关阅读:
    20155204 实验3《敏捷开发与XP实践》实验报告
    20155204 2016-2017-2 《Java程序设计》第10周学习总结
    20155204 2016-2017-2 《Java程序设计》第9周学习总结
    实验二 面向对象的程序设计
    20155204 2016-2017-2 《Java程序设计》第8周学习总结
    20155204 2016-2017-2 《Java程序设计》第7周学习总结
    20155204 《Java程序设计》实验一(Java开发环境的熟悉)实验报告
    20155204 2016-2017-2 《Java程序设计》第6周学习总结
    # 20155204 2016-2017-2 《Java程序设计》第五周学习总结
    20155204 2016-2017-2 《Java程序设计》第4周学习总结
  • 原文地址:https://www.cnblogs.com/Answer1215/p/5183514.html
Copyright © 2011-2022 走看看