wfatec / notebook

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Redux踩坑系列--Reducer

wfatec opened this issue · comments

Reducer简介

reducer实际上是真正作用于redux中state部分的纯函数,用于接收dispatch传过来的action对象,action对象通常是这种形式:

{
  type: ADD_TODO,
  payload: “balabala...”
}

其中payload可以放入任何类型数据。当dispatch(action)之后,就轮到reducer大展神威了,它会根据ADD_TODO进行匹配(一般通过switch/case),执行相应的纯函数。

对于纯函数网上有很多的详解,这里简单说一下我的理解,其实就一个公式:f(x)===f(x);任意函数只要在任意情况下满足该公式,即纯函数

那么reducer作为纯函数一般形式是什么样呢?如下:

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    case ADD_TODO:
      return Object.assign({}, state, {
        todos: [
          ...state.todos,
          {
            text: action.text,
            completed: false
          }
        ]
      })
    default:
      return state
  }
}

其实现的功能主要有:

  1. 接收原始statedispatch的参数action
  2. 根据actiontype属性找到对应的执行函数
  3. action.type未匹配,则原样返回接收的state

没错,这就是reducer的所有功能 :)

combineReducers

reducer本身没有什么问题,但随着项目的复杂度急剧增加,此时将所有action.type的执行函数都写在一个文件里明显会带来维护上的困难,有没有什么方法能够使得各自模块的reducer能够各自维护,再统一合并到最终传给createStore的rootReducer中去呢?这个时候就到combineReducers登场的时候了。

先来看一下combineReducers的调用方式:

import { combineReducers } from 'redux'
import todos from './todos'
import counter from './counter'

export default combineReducers({
  todos,
  counter
})

其中todos和counter为已定义的分片reducer。

它主要实现的功能如下:

  1. 将不同模块的reducer函数合并到rootReducer
  2. 将reducer执行结果返回到该reducer传入combineReducers时对应的key下如此处的todos和counter

这里有一些需要着重提示一下:

所有传入的reducer会依次执行

这也就意味着不同reducer之间的执行结果会对之后的reducer执行造成影响,例如当todos中的reducer未匹配到对应的action时,如果在default中未返回传入state,或返回了错误的值,则在counter中将发生错误。因此我们在定义reducer时需要遵守如下约定:

  1. 入参中的state设置默认值
  2. 必须在switch/case最后定义default并返回传入的state
  3. 尽量避免不同reducer中使用相同的actionType

以上