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