Redux初见
本文记录的是自己对redux的学习和理解,希望可以简洁易懂,入门@H_502_3@redux,一步步的走进@H_502_3@redux!
Redux是什么
@H_502_3@Redux是@H_502_3@JavaScript应用的状态容器,提供可预测化的状态管理,让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。不仅于此,它还提供超爽的开发体验。
核心概念
【@H_502_3@store】保存应用状态全局单一
【@H_502_3@state】所有@H_502_3@state以key-value的形式存储在@H_502_3@store中
【@H_502_3@action】描述发生什么的对象,触发@H_502_3@action是唯一改变@H_502_3@state的方式,@H_502_3@action本质上是一个普通js对象,必必须一个@H_502_3@type字段,值为字符串常量
Redux常用方法
createStore(reducer,[initialState])
创建一个Redux @H_502_3@store来以存放应用中所有的@H_502_3@state。
combineReducers(reducers)
随着应用复杂度上升,数据源逐渐变混乱,导致组件内部数据调用十分复杂,会产生数据冗余或者混用等情况,需要对@H_502_3@reducer函数进行拆分,拆分后的每一模块独立负责管理@H_502_3@state的一部分。@H_502_3@combineReducers函数的作用是,返回一个最终的@H_502_3@rootReducer函数,@H_502_3@rootReducer做的事情是得到一个由多个不同@H_502_3@reducer函数作为value(key可以自定义)的对象。
const module1Reducer = combineReducers( module1_key1: module1_reducer1 ); const rootReducer = combineReducers( key1: reducer1,module1: module1Reducer ); const store = createStore(rootReducer); // store中保存的state结构如下 { key1: reducer1(state.key1,action),module1: { module1_key1: (state.module1.module1_key1,action) } }
总结一下,@H_502_3@state对象的结构由传入的多个@H_502_3@reducer的key决定,可以根据模块拆分的细粒度,考虑是否需要嵌套使用@H_502_3@combineReducers,整个应用的数据大致分来两类:普通data和ui状态
+ data - 服务器响应的数据 - 缓存数据 - 本地尚未持久化到服务器的数据 - 用户输入 - ... + ui状态 - 激活的路由 - 被选中的Tab标签 - 是否显示加载动画 - 分页器状态 - ...
设计@H_502_3@state结构时,尽量把@H_502_3@state范式化,不要存在嵌套不同类型的对象的情况。把数据放到一个对象(列表)中,每个数据用@H_502_3@id作为主键。不同类型的对象通过@H_502_3@id引用数据,这样数据发生改变的时候,只需要修改一处地方,减少数据冗余或者混用。
applyMiddleware(...middlewares)
首先要介绍一下什么是@H_502_3@middlewares,@H_502_3@middlewares用于包装@H_502_3@store.dispatch,扩展其功能,在发起action之后,到达reducer之前执行一些逻辑,有点类似是aop的一种实现。
applyMiddleware大致实现:
function applyMiddleware(store,middlewares) { middlewares = middlewares.slice() middlewares.reverse() // 暂存dispatch let dispatch = store.dispatch // 包装dispatch middlewares.forEach(middleware => dispatch = middleware(store)(dispatch) ) return {...store,{ dispatch }) }
理解了@H_502_3@applyMiddleware的逻辑,自定义一个@H_502_3@middleware大致如下
function(store){ // pass store.dispatch to next return function(next){ // return dispatch return function(action){ // implement middleware logic } } }
bindActionCreators(actionCreators,dispatch)
参数actionCreators如果为函数 把 @H_502_3@action creators 转成拥有同名@H_502_3@keys的对象,但使用 @H_502_3@dispatch 把每个@H_502_3@action creator包围起来,返回新的对象
参数actionCreators如果为对象,若actionCreators[key]为函数,用@H_502_3@dispatch把每个 actionCreators[key]包围起来,返回新的对象
compose(...functions)
组合store enhance,applyMiddleware 和 redux-devtools就是store enhance
React-redux桥接
@H_502_3@Redux本身只提供应用状态和数据流管理,除了和@H_502_3@React一起用外,还支持其它界面库,且没有任何依赖。要在@H_502_3@React的项目中使用@H_502_3@Redux,比较好的方式是借助react-redux这个库来做连接.
provider
为整个应用提供@H_502_3@store数据,做的事情是把@H_502_3@store作为props传递到每一个被@H_502_3@connet()包装的组件
connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options])
connect(...args)(component)返回一个与@H_502_3@Redux store连接的组件类,下面简单讲解一下@H_502_3@connect方法的参数
mapStateToProps(state,[ownProps]) [Function]
该回调函数必须返回一个纯对象,这个对象会与被包装的组件的props做merge合并
@H_502_3@mapStateToProps可以做一些数据的format, filter,compose操作,保证数据在组件层面的方便使用
mapDispatchToProps(dispatch,[ownProps]) [Object or Function]
@H_502_3@mapDispatchToProps参数为@H_502_3@Object,每个定义在该对象的函数都将被当作@H_502_3@Redux action creator,其中所定义的方法名将作为属性名,合并到被包装的组件的props中,实现的效果:执行component.prop.checkout()实际上是@H_502_3@dispatch了一个@H_502_3@action,这样做的好处是component与redux的解耦,component根本不知道redux的存在。
// action creator返回对象 mapDispatchToProps = { // action creator checkout: function actionCreator(productId){ return { type: types.ADD_TO_CART,productId } } } // action creator返回函数,thunk mapDispatchToProps = { // action creator checkout: function actionCreator(productId){ action creator 返回一个thunk, thunk的参数为 dispatch 和 getState return (dispatch,getState) => { if (getState().products.byId[productId].inventory > 0) { dispatch(addToCartUnsafe(productId)) } } } } // 最终被绑定的组件props component.props.checkout = function () { return dispatch(actionCreator.apply(undefined,arguments)); }
mapDispatchToProps(dispatch,[ownProps]) = function(){ return { checkout: () => { dispatch(actionCreator()) } } } // 最终被绑定的组件.props component.props.checkout = function () { return dispatch(actionCreator.apply(undefined,arguments)); } // 使用bindActionCreators mapDispatchToProps(dispatch,[ownProps]) = function(){ return bindActionCreators(actionCreator,dispatch) } // 最终被绑定的组件props component.props.actionCreator = function () { return dispatch(actionCreator.apply(undefined,arguments)); } // 使用 bindActionCreators mapDispatchToProps(dispatch,[ownProps]) = function(){ return bindActionCreators({ ‘checkout’: actionCreator },dispatch) } // 最终被绑定的组件props component.props.checkout = function () { return dispatch(actionCreator.apply(undefined,arguments)); }
使用redux之后应用的数据流向
dispatch(actionCreator)=> Reducer => (state,action) => state