redux 入门之 reducer 介绍和使用
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 // 根据reducers这个对象的key,取到reducer函数,并传入对应的 state const combineReducers = function combineReducers (reducers) { return (state = {}, action) { Object.keys(reducers).reduce((initialState, key) => { initialState[key] = reducers[key](state[key], action) return initialState },{}) } }
这个函数返回一个 rootReducer,然后 createStore 接收 rootReducer,在 createStore 内部会调用一次 dispatch(init),rootReducer 会执行,所有我们制定的 reducrs 对象中的 key 都会被添加到 一个初始化 initialState 中,遍历将每个子级 state 添加到 initialState 。init 的时候,state[key] 是 undefined,每个 reducer 函数有初始值 返回。以后的 dispatch ,因为有了 state tree,state[key] 都可以取到值了。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: redux 入门之 store 状态机
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论