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
多个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
},{})
}
}
未完