FilterLink组件的currentFilter, onClick等属性要得来回传递多次,而且更重要的是定义组件的的时候onClick等事件与该组件要得有更直观的依赖关系才行。

使用FilterLink组件的时候要知道currentFilter才可以调用,在最上层里调用时必须知道这个值才可以,所以Footer里还要得接收visibilityFilter的值才行。

这样以来父级层里要传递很多参数才可以使用。

首先调用Footer的时候我们这样来修改,更直观一些

//修改前:
<Footer 
      visibilityFilter={visibilityFilter}
      onFilterClick={filter => {
        store.dispatch({
          type: 'SET_VISIBILITY_FILTER',
          filter
        });
      }} />

//修改后:
<Footer />

这样Footer组件就不用去管,visibilityFilteronFilterClick


// Footer 容器组件
//修改前:
const Footer = ({
  visibilityFilter,
  onFilterClick
}) => (

  <p>
    Show: 
    {' '}
    <FilterLink
      filter='SHOW_ALL'
      currentFilter={visibilityFilter}
      onClick={onFilterClick}>ALL</FilterLink>
    {' '}
    <FilterLink
      filter='SHOW_ACTIVE'
      currentFilter={visibilityFilter}
      onClick={onFilterClick}>Active</FilterLink>
    {' '}
    <FilterLink
      filter='SHOW_COMPLETED'
      currentFilter={visibilityFilter}
      onClick={onFilterClick}>Completed</FilterLink>
  </p>  
);
//修改后:
const Footer = () => (  
  <p>
    Show: 
    {' '}
    <FilterLink
      filter='SHOW_ALL'>ALL</FilterLink>
    {' '}
    <FilterLink
      filter='SHOW_ACTIVE'>Active</FilterLink>
    {' '}
    <FilterLink
      filter='SHOW_COMPLETED'>Completed</FilterLink>
  </p>  
);

这样一来要得考虑FilterLink怎么定义onClick的行为和当前过滤状态了

//FilterLink 组件
//修改前:
const FilterLink = ({
  filter, 
  children, 
  currentFilter,
  onClick
}) => {
  if (filter === currentFilter){
    return <span>{children}</span>;
  }
  return (
    <a href='#'
      onClick={e => {
        e.preventDefault();
        onClick(filter);
    }}>
      {children}
    </a>
  );
}
//修改后:  //分离数据只去管怎么展示
const Link = ({     //分离展示组件为Link
//  filter, 
  active,
  children, 
//  currentFilter,
  onClick
}) => {
  if (active){
    return <span>{children}</span>;
  }
  return (
    <a href='#'
      onClick={e => {
        e.preventDefault();
        onClick();      //去掉filter
    }}>
      {children}
    </a>
  );
}

class FilterLink extends Component {

  componentDidMount() {  //React初始化渲染不会调用,更新后调用。
    this.unsubscribe = store.subscribe(() => this.forceUpdate());
    //forceUpdate说明:https://react.bootcss.com/react/docs/react-component.html#forceupdate
  }

  componentWillUnmount() {
    this.unsubscribe();  //这个实在搞不懂是取消监听的还是更新状态用的~ OTL
  }

  render() {
    const props = this.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>
    );
  }
}

对这一部分代码的目的不太理解查看原文慢慢理解吧。好像现在不更新状态也没什么问题。

class FilterLink extends Component {
  componentDidMount() {
    this.unsubscribe = store.subscribe(() =>
      this.forceUpdate()
    );
  }

  componentWillUnmount() {
    this.unsubscribe();
  }
}
render() { ... }

React provides a special forceUpdate method on the component instances to force their re-rendering. We're going to use it together with store.subscribe method so that any time the store state changes, we force update the container components.

We perform the subscription inside the componentDidMount lifecycle method. So it's important to unsubscribe inside the componentWillUnmount method. Note that we don't actually have the unsubscribe function, but this is the return value of the store subscribe method, so we can keep it, and then call it inside componentWillUnmount.

Step2: TodoList 容器组件

//修改前:
<TodoList
 todos={getVisibleTodos(todos,visibilityFilter)}
 onTodoClick={id =>
   store.dispatch({
     type: 'TOGGLE_TODO',
     id
   })
 } />
//修改后:
<VisibleTodoList />


class VisibleTodoList extends Component {
  componentDidMount() {  //React初始化渲染不会调用,更新后调用。
    this.unsubscribe = store.subscribe(() => this.forceUpdate());
    //forceUpdate说明:https://react.bootcss.com/react/docs/react-component.html#forceupdate
  }

  componentWillUnmount() {
    this.unsubscribe();  //这个实在搞不懂是取消监听的还是更新状态用的~ OTL
  }
  render() {
    const props = this.props;
    const state = store.getState();
    return (
      <TodoList
        todos={
          getVisibleTodos(
            state.todos,
            state.visibilityFilter
          )
        }
        onTodoClick={id =>
          store.dispatch({
            type: 'TOGGLE_TODO',
            id
          })
        }
      />      
    );
  }
}

Step3: AddTodo 组件

//修改前:
<AddTodo
      onAddClick={text =>
        store.dispatch({
          type: 'ADD_TODO',
          id: nextTodoId++,
          text
        })
      }
    />
//修改后:
<AddTodo />
//AddTodo 组件
const AddTodo = () => {
  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>
  );
};

Step4: TodoApp组件

// TodoApp 组件

//修改前:
const TodoApp = ({
  todos,
  visibilityFilter
}) => (
  <div>
    <AddTodo />
    <VisibleTodoList />
    <Footer />
  </div>
);

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

store.subscribe(render);
render();

//修改后:
const TodoApp = () => (
  <div>
    <AddTodo />
    <VisibleTodoList />
    <Footer />
  </div>
);


ReactDOM.render(
    <TodoApp />,
    document.getElementById('root')
);

//最终代码:http://jsbin.com/bocevor/edit?js,output

异步请求

http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html

https://github.com/dwqs/blog/issues/35

Redux-saga总结 含轮询中间件例子