Action/Reducer/Store

首先,先看看第一张图,图中展示了Redux的单向数据流,以及Action、Reducer和Store这三个核心概念。

下面就围绕上图,非别介绍Action、Reducer和Store这三个概念。

Action和Action Creator

Action是一个对象,用来代表所有会引起状态(state)变化的行为(例如服务端的响应,页面上的用户操作)。

假如我们要实现一个任务管理系统,那么添加任务的Action对象就会是下面的形式:

{
type: 'ADD_TASK',
name: 'Read ES6 spec',
category: 'Reading'
}

Action对象是行为的描述,一般都会包含下面的信息:

  • 一个字符串类型的type字段来表示将要执行的动作
  • 需要传递给应用的其他数据信息(例子中的name和category),数据形式用户可以自定义

Action通过Action创建函数(Action Creator)来创建,Action Creator是一个函数,最终返回一个Action对象。

对于添加任务这个行为,对应的Action Creator如下:

function addTask(name, category) {
return {
type: ADD_TASK,
name,
category
};
}

Reducer

Action对象仅仅是描述了行为的相关信息,至于如何通过特定的行为来更新state,就需要看看Reducer了。

关于Reducer,最简单的描述就是:

  • Reducer是一个函数
  • 该函数接收两个参数,一个旧的状态previousState和一个Action对象
  • 返回一个新的状态newState

根据上面的描述,Reducer函数就可以表示为:

(previousState, action) => newState

Reducer函数的形式通常如下:

function reducer(state = [], action) {
// 处理不同action的代码
switch (action.type) {
case SPECIAL_ACTION:
// 根据SPECIAL_ACTION action更新state
// 返回新的state
default:
return state
}
}

Store

Actions描述了"what happened"的事实,Reducers则根据这些actions来更新state,而Store则是Actions和Reducers连接在一起的对象。

Store是Redux中数据的统一存储,维护着state的所有内容,所以Store的主要功能就是:

  • 维护应用的state内容
  • 提供getState()方法获取 state
  • 提供dispatch(action)方法更新 state
  • 提供subscribe(listener)方法注册监听器

看到Store提供的方法,就可以把Action、Reducer和Store联系在一起了:

  1. Store通过dispatch(action)方法来接收不同的Action
  2. 根据Action对象的type和数据信息,Store对象可以通过Reducer函数来更新state的内容

Middleware

下面就来看看第二张图,跟第一张图的差别不大,只是增加了中间件(Middleware)来处理Action。

在Redux中,Middlerwares主要的作用就是处理Action,Redux中的Action必须是一个plain object。但是为了实现异步的Action或其他功能,这个Action可能就是一个函数,或者是一个promise对象。这是就需要中间件帮助来处理这种特殊的Action了。

也就是说,Redux中的Middleware会对特定类型action做一定的转换,所以最后传给reducer的action一定是标准的plain object。

针对Action的特征,Reudx Middleware可以采取不同的操作:

  • 可以选择传递给下一个中间件,如:next(action)
  • 可以选择跳过某些中间件,如:dispatch(action)
  • 或者更直接了当的结束传递,如:return。

Redux中常用的中间件:

  • redux-thunk:action可以是一个函数,用来发起异步请求。
  • redux-promise:action可以是一个promise对象,用来更优雅的进行异步操作。
  • redux-logger:action就是一个标准的plain object,用来记录action和nextState的。

react-redux

经过前面的介绍,我们已经看到了Redux中的一些核心概念。Redux跟React没有直接的关系,本身可以支持React、Angular、Ember等等框架。

通过react-redux这个库,可以方便的将react和redux结合起来:react负责页面展现,redux负责维护/更新数据状态。

到这里,第三张图就展示了react-redux这个库的工作原理,react和redux是怎么联系到一起的。

react-redux中提供了两个重要功能模块Provider和connect,这两个模块保证了react和redux之间的通信,下面就分别看看这两个模块。

Provider

通过Provider的代码可以看到,Provide本质上是一个react组件。

export default class Provider extends Component {
getChildContext() {
return { store: this.store }
} constructor(props, context) {
super(props, context)
this.store = props.store
} render() {
const { children } = this.props
return Children.only(children)
}
}

Provider组件主要用到了react通过context属性,可以将属性(props)直接给子孙component,无须通过props层层传递,从而减少组件的依赖关系。

connect

connect方法的主要作用就是让Component与Store进行关联, Store的数据变化可以及时通知Views重新渲染。

任何一个通过connect()函数处理过的组件都可以得到一个dispatch方法作为组件的props,以及得到全局state中的所有内容。

通过源码]可以看到,connect函数运行后,会返回一个wrapWithConnect函数,该函数可以接收一个react组件,然后返回一个经过处理的Connect组件。

return function wrapWithConnect(WrappedComponent) {
class Connect extends Component {
constructor(props, context) {
// 从祖先Component处获得store
this.store = props.store || context.store
this.stateProps = computeStateProps(this.store, props)
this.dispatchProps = computeDispatchProps(this.store, props)
this.state = { storeState: null }
// 对stateProps、dispatchProps、parentProps进行合并
this.updateState()
}
shouldComponentUpdate(nextProps, nextState) {
// 进行判断,当数据发生改变时,Component重新渲染
if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
this.updateState(nextProps)
return true
}
}
componentDidMount() {
// 改变Component的state
this.store.subscribe(() = {
this.setState({
storeState: this.store.getState()
})
})
}
render() {
// 生成包裹组件Connect
return (
<WrappedComponent {...this.nextState} />
)
}
}
Connect.contextTypes = {
store: storeShape
}
return Connect;
}

详细内容和demo

文中很多Redux的概念都是进行了简单的介绍,更多详细的介绍可以参考,GitHub地址:WilberTian/StepByStep-Redux

每篇文章的结尾都会有一些简单的demo 代码,帮助理解文章中介绍的内容。

总结

文中结合三张图片介绍了Redux中的一些核心概念,以及React和Redux之间通过react-redux这个库进行交互。

更多详细的内容,已经整理到了GitHub上了(WilberTian/StepByStep-Redux),通过这些介绍以及demo的运行结果,一定能对Redux有一个比较基本的认识。

最新文章

  1. JS打印对象的方法&amp;将Object转换为String的函数
  2. iOS开发,URL编码和解码
  3. C#委托理解(个人观点)
  4. Java中FileOutputStream和FileInputStream使用例子
  5. Excel加密的Sheet如何hack
  6. 实践JAVA wait(), notify(),sleep方法--一道多线程的面试题
  7. ios中怎么样调节占位文字与字体大小在同一高度
  8. ngnix 下配置多域名跳转 配置方法
  9. [unity3d]手游资源热更新策略探讨
  10. Away3D基础之摄像机
  11. SQL UNION 和 UNION ALL 操作符
  12. linux下类似Bus Hound的工具
  13. UltraEdit-32 温馨提示:右协会,取消 bak文件
  14. iOS 即时通讯 + 仿微信聊天框架 + 源码
  15. 一个简易内存池(C++)
  16. JDBC【事务、元数据、改造JDBC工具类】
  17. ActiveMQ系列之二:ActiveMQ安装和基本使用
  18. Javascript高级编程学习笔记(29)—— BOM(3)location对象
  19. cf250D. The Child and Sequence(线段树 均摊复杂度)
  20. plsql 导出查询结果

热门文章

  1. python实现二叉树和它的七种遍历
  2. Swiper滑动Html5手机浏览器自适应
  3. 2. QT窗体间值的传递
  4. ListView加载两种以上不同的布局
  5. AsyncTask使用注意事项
  6. 1217.1——OC准备
  7. virtual box 改变已经创建的虚拟系统分配的硬盘
  8. n个数的最大公约、最小公倍数
  9. [汇编语言]-第十章 ret,retf,call指令
  10. [原]用C#模拟实现扑克牌发牌、排序程序。