redux 入门之 reducer

3,075 阅读3分钟

reducer

  • 为什么叫reducer
    大概是由于reducer函数都能作为数组的reduce方法的参数,所以叫reducer的吧。
  • Array中的reduce
    reduce需要两个参数,一个是回调函数,一个是初始值,没有初始值,会默认把数组第一个当初始值,并从第二个开始

模拟数组的reduce方法

Array.prototype.reduce = function reduce (callback, init) {
  var i = 0;
  if(typeof init === 'undefined') {
    init = this[0];
    i = 1;
  }
  if(typeof callback !== 'function') {
    throw new Error(callback + ' is not function')
  }
  for( ;i< this.length; i++ ) {
    init = callback(init, this[i])
  }
  return init ;
}

reduce的使用

var ary = [1,2,3];
console.log(ary.reduce((initialValue, next) => {
  console.log(initialValue, next);
  return next;
},0))
// 01  12  23  3

写一个简单的reducer

function reducer (initialValue, next) {
  console.log(initialValue, next)
  switch (next) {
    case 1:
      return next;
      break;
    default:
      return initialValue
  }
}
// 这个reducer 判断传入的值next。是1 的话 返回结果是 next 也就是1 ,所以最后结果都是1
console.log(ary.reduce(reducer))
// 12  13  1

reducer在redux中的作用

reducer的作用就是设计state结构,它可以给定state 的初始值,更重要的是告诉store,根据对应的action如何更新state。 通常我们的store需要多个reducer组合,成为我们最后的state tree

注意点

  • 保持reducer 的纯净

通常我们的reducer是纯函数(pure function) 即固定的输入返回固定的输出,没有副作用,没有API请求... 等等,之后我们说为什么这么做。
通常我们在处理业务中,比如请求一个列表的数据并渲染。
举个栗子

const initialState = {
  code: -1,
  data: [],
  isFetching: false
};
//初始化我们的state,也就是没有请求之前,我们根据接口的数据格式做一个模拟

function List(state = initialState, action) {
  switch (action.type) {
// 这里的types 通常是我们保存这种常量的一个对象

    case types.FETCH_LIST_SUCCESS:
      return {...state, data:action.data,isFetching:false};
    case types.FETCHING_LIST:
      return {...state, isFetching: true}
    case types.FETCH_LIST_FAILURE:
      return {...state, isFetching:false};
    default:
      return state
    }
}

我们的reducer函数就是根据请求的状态返回不同的数据,但是数据格式是一定的。Fetching就是 请求过程中,比如我们做一个loading效果可能需要这个。然后type是success就是成功我们返回数据。这些请求都放到actions 中了,actions去处理逻辑,数据API,重组数据。只需要传给reducer函数数据结果就ok了。

为什么要重新返回一个对象。

我们可以看到reducer函数在拿到数据后通过Object.assign 重新返回一个对象,直接state.data 修改,返回state不行吗?

首先 我们默认的初始state是不能直接改变的,我们的reducer函数 在数据failure的时候 return了默认的state,这个initialState 是不应该被修改的。

另外,我们的react组件 会多次接受store传入props,每一次都应该是一个全新的对象引用,而不是同一个引用。比如我们需要比较两次传入的props,利用componentWillReciveProps(nextProps) 比较this.props 跟nextProps,肯定是需要两个对象空间的,不然是同一个对象引用也就没法比较了。

所以redux 中的reducer 函数要求我们必须返回新的对象state

redux文档-reducer

多个reducer组合成我们的state tree

通常我们会引入redux提供的一个函数

import { combineReducers } from 'redux'

其实combineReducers做的事情很简单,顾名思义就是合并多个reducer
比如我们一个项目有多个reducer但是最后需要合并成一个,然后告诉store生成state tree,再注入Provider组件,先不关注Provider的问题。我们看一下combineReducers的具体实现

//首先我们组合得到的reducer仍旧是一个函数
//这个reducer会整合所有的reducer
//然后根据我们定义的状态树的格式返回一个大的state tree

const combineReducers = function combineReducers (reducers) {
  return (state = {}, action) {
    Object.keys(reducers).reduce((initialState, key) => {
      initialState[key] = reducers[key](state[key], action)
      return initialState
    },{})

  }
}

未完