react redux 异步为什么需要异步action

Redux 莞式教程 之 简明篇 - CNode技术社区
有逼格的JSer
Redux 简明教程
原文链接(保持更新):
本教程深入浅出,配套 简明教程、(源码精读)以及文档注释丰满的
等一条龙服务
§ 为什么要用 Redux
当然还有 、、 等状态管理库可供选择
抛开需求讲实用性都是耍流氓,因此下面由我扮演您那可亲可爱的产品经理
⊙ 需求 1:在控制台上记录用户的每个动作
不知道您是否有后端的开发经验,后端一般会有记录访问日志的中间件
例如,在 Express 中实现一个简单的 Logger 如下:
var loggerMiddleware = function(req, res, next) {
console.log('[Logger]', req.method, req.originalUrl)
app.use(loggerMiddleware)
每次访问的时候,都会在控制台中留下类似下面的日志便于追踪调试:
[Logger] GET
[Logger] POST /login
[Logger] GET
/user?uid=10086
如果我们把场景转移到前端,请问该如何实现用户的动作跟踪记录?
我们可能会这样写:
/** jQuery **/
$('#loginBtn').on('click', function(e) {
console.log('[Logger] 用户登录')
$('#logoutBtn').on('click', function() {
console.log('[Logger] 用户退出登录')
/** MVC / MVVM 框架(这里以纯 Vue 举例) **/
methods: {
handleLogin () {
console.log('[Logger] 用户登录')
handleLogout () {
console.log('[Logger] 用户退出登录')
上述 jQuery 与 MV* 的写法并没有本质上的区别
记录用户行为代码的侵入性极强,可维护性与扩展性堪忧
⊙ 需求 2:在上述需求的基础上,记录用户的操作时间
哼!最讨厌就是改需求了,这种简单的需求难道不是应该一开始就想好的吗?
呵呵,如果每位产品经理都能一开始就把需求完善好,我们就不用加班了好伐
显然地,前端的童鞋又得一个一个去改(当然 编辑器 / IDE 都支持全局替换):
/** jQuery **/
$('#loginBtn').on('click', function(e) {
console.log('[Logger] 用户登录', new Date())
$('#logoutBtn').on('click', function() {
console.log('[Logger] 用户退出登录', new Date())
/** MVC / MVVM 框架(这里以 Vue 举例) **/
methods: {
handleLogin () {
console.log('[Logger] 用户登录', new Date())
handleLogout () {
console.log('[Logger] 用户退出登录', new Date())
而后端的童鞋只需要稍微修改一下原来的中间件即可:
var loggerMiddleware = function(req, res, next) {
console.log('[Logger]', new Date(), req.method, req.originalUrl)
app.use(loggerMiddleware)
⊙ 需求 3:正式上线的时候,把控制台中有关 Logger 的输出全部去掉
难道您以为有了 UglifyJS,配置一个 drop_console: true 就好了吗?图样图森破,拿衣服!
请看清楚了,仅仅是去掉有关 Logger 的 console.log,其他的要保留哦亲~~~
于是前端的童鞋又不得不乖乖地一个一个注释掉(当然也可以设置一个环境变量判断是否输出,甚至可以重写 console.log)
而我们后端的童鞋呢?只需要注释掉一行代码即可:// app.use(loggerMiddleware),真可谓是不费吹灰之力
⊙ 需求 4:正式上线后,自动收集 bug,并还原出当时的场景
收集用户报错还是比较简单的,,然后根据 Source Map 定位到源码(但一般查不出什么)
但要完全还原出当时的使用场景,几乎是不可能的。因为您不知道这个报错,用户是怎么一步一步操作得来的
就算知道用户是如何操作得来的,但在您的电脑上,测试永远都是通过的(不是我写的程序有问题,是用户用的方式有问题)
相对地,后端的报错的收集、定位以及还原却是相当简单。只要一个 API 有 bug,那无论用什么设备访问,都会得到这个 bug
还原 bug 也是相当简单:把数据库备份导入到另一台机器,部署同样的运行环境与代码。如无意外,bug 肯定可以完美重现
在这个问题上拿后端跟前端对比,确实有失公允。但为了鼓吹 Redux 的优越,只能勉为其难了
实际上 jQuery / MV* 中也能实现用户动作的跟踪,用一个数组往里面 push 用户动作即可
但这样操作的意义不大,因为仅仅只有动作,无法反映动作前后,应用状态的变动情况
为何前后端对于这类需求的处理竟然大相径庭?后端为何可以如此优雅?
原因在于,后端具有统一的入口与统一的状态管理(数据库),因此可以引入中间件机制来统一实现某些功能
多年来,前端工程师忍辱负重,操着卖白粉的心,赚着买白菜的钱,一直处于程序员鄙视链的底层
于是有大牛就把后端 MVC 的开发思维搬到前端,将应用中所有的动作与状态都统一管理,让一切有据可循
使用 Redux,借助
可以实现出“华丽如时光旅行一般的调试效果”
实际上就是开发调试过程中可以撤销与重做,并且支持应用状态的导入和导出(就像是数据库的备份)
而且,由于可以使用日志完整记录下每个动作,因此做到像 Git 般,随时随地恢复到之前的状态
由于可以导出和导入应用的状态(包括路由状态),因此还可以实现前后端同构(服务端渲染)
当然,既然有了动作日志以及动作前后的状态备份,那么还原用户报错场景还会是一个难题吗?
首先要区分 store 和 state
state 是应用的状态,一般本质上是一个普通对象
例如,我们有一个 Web APP,包含 计数器 和 待办事项 两大功能
那么我们可以为该应用设计出对应的存储数据结构(应用初始状态):
/** 应用初始 state,本代码块记为 code-1 **/
counter: 0,
store 是应用状态 state 的管理者,包含下列四个函数:
getState() # 获取整个 state
dispatch(action) # ※ 触发 state 改变的【唯一途径】※
subscribe(listener) # 您可以理解成是 DOM 中的 addEventListener
replaceReducer(nextReducer) # 一般在 Webpack Code-Splitting 按需加载的时候用
二者的关系是:state = store.getState()
Redux 规定,一个应用只应有一个单一的 store,其管理着唯一的应用状态 state
Redux 还规定,不能直接修改应用的状态 state,也就是说,下面的行为是不允许的:
var state = store.getState()
state.counter = state.counter + 1 // 禁止在业务逻辑中直接修改 state
若要改变 state,必须 dispatch 一个 action,这是修改应用状态的不二法门
现在您只需要记住 action 只是一个包含 type 属性的普通对象即可
例如 { type: 'INCREMENT' }
上面提到,state 是通过 store.getState() 获取,那么 store 又是怎么来的呢?
想生成一个 store,我们需要调用 Redux 的 createStore:
import { createStore } from 'redux'
const store = createStore(reducer, initialState) // store 是靠传入 reducer 生成的哦!
现在您只需要记住 reducer 是一个 函数,负责更新并返回一个新的 state
而 initialState 主要用于前后端同构的数据同步(详情请关注 React 服务端渲染)
上面提到,action(动作)实质上是包含 type 属性的普通对象,这个 type 是我们实现用户行为追踪的关键
例如,增加一个待办事项 的 action 可能是像下面一样:
/** 本代码块记为 code-2 **/
type: 'ADD_TODO',
payload: {
content: '待办事项1',
completed: false
当然,action 的形式是多种多样的,唯一的约束仅仅就是包含一个 type 属性罢了
也就是说,下面这些 action 都是合法的:
/** 如下都是合法的,但就是不够规范 **/
type: 'ADD_TODO',
content: '待办事项1',
completed: false
type: 'ADD_TODO',
abcdefg: {
content: '待办事项1',
completed: false
虽说没有约束,但最好还是遵循
如果需要新增一个代办事项,实际上就是将 code-2 中的 payload “写入” 到 state.todos 数组中(如何“写入”?在此留个悬念):
/** 本代码块记为 code-3 **/
counter: 0,
content: '待办事项1',
completed: false
刨根问底,action 是谁生成的呢?
⊙ Action Creator
Action Creator 可以是同步的,也可以是异步的
顾名思义,Action Creator 是 action 的创造者,本质上就是一个函数,返回值是一个 action(对象)
例如下面就是一个 “新增一个待办事项” 的 Action Creator:
/** 本代码块记为 code-4 **/
var id = 1
function addTodo(content) {
type: 'ADD_TODO',
payload: {
content: content, // 待办事项内容
completed: false
// 是否完成的标识
将该函数应用到一个表单(假设 store 为全局变量,并引入了 jQuery ):
&--! 本代码块记为 code-5 --&
&input type=&text& id=&todoInput& /&
&button id=&btn&&提交&/button&
$('#btn').on('click', function() {
var content = $('#todoInput').val() // 获取输入框的值
var action = addTodo(content) // 执行 Action Creator 获得 action
store.dispatch(action) // 改变 state 的不二法门:dispatch 一个 action!!!
&/script&
在输入框中输入 “待办事项2” 后,点击一下提交按钮,我们的 state 就变成了:
/** 本代码块记为 code-6 **/
counter: 0,
content: '待办事项1',
completed: false
content: '待办事项2',
completed: false
通俗点讲,Action Creator 用于绑定到用户的操作(点击按钮等),其返回值 action 用于之后的 dispatch(action)
刚刚提到过,action 明明就没有强制的规范,为什么 store.dispatch(action) 之后,
Redux 会明确知道是提取 action.payload,并且是对应写入到 state.todos 数组中?
又是谁负责“写入”的呢?悬念即将揭晓…
§ Reducer
Reducer 必须是同步的纯函数
用户每次 dispatch(action) 后,都会触发 reducer
reducer 的实质是一个函数,根据 action.type 来更新 state 并返回 nextState
最后会用 reducer 的返回值 nextState 完全替换掉原来的 state
注意:上面的这个 “更新” 并不是指 reducer 可以直接对 state 进行修改
Redux 规定,须先复制一份 state,在副本 nextState 上进行修改操作
例如,可以使用 lodash 的 deepClone,也可以使用 Object.assign / map / filter/ ... 等返回副本的函数
在上面 Action Creator 中提到的 待办事项的 reducer 大概是长这个样子 (为了容易理解,在此不使用 ES6 / ):
/** 本代码块记为 code-7 **/
var initState = {
counter: 0,
function reducer(state, action) {
// ※ 应用的初始状态是在第一次执行 reducer 时设置的(除非是服务端渲染) ※
if (!state) state = initState
switch (action.type) {
case 'ADD_TODO':
var nextState = _.deepClone(state) // 用到了 lodash 的深克隆
nextState.todos.push(action.payload)
return nextState
// 由于 nextState 会把原 state 整个替换掉
// 若无修改,必须返回原 state(否则就是 undefined)
return state
通俗点讲,就是 reducer 返回啥,state 就被替换成啥
store 由 Redux 的 createStore(reducer) 生成
state 通过 store.getState() 获取,本质上一般是一个存储着整个应用状态的对象
action 本质上是一个包含 type 属性的普通对象,由 Action Creator (函数) 产生
改变 state 必须 dispatch 一个 action
reducer 本质上是根据 action.type 来更新 state 并返回 nextState 的函数
reducer 必须返回值,否则 nextState 即为 undefined
实际上,state 就是所有 reducer 返回值的汇总(本教程只有一个 reducer,主要是应用场景比较简单)
Action Creator =& action =& store.dispatch(action) =& reducer(state, action) =& 原 state state = nextState
⊙ Redux 与传统后端 MVC 的对照
传统后端 MVC
数据库实例
数据库中存储的数据
dispatch(action)
用户发起请求
action: { type, payload }
type 表示请求的 URL,payload 表示请求的数据
路由 + 控制器(handler)
reducer 中的 switch-case 分支
路由,根据 action.type 路由到对应的控制器
reducer 内部对 state 的处理
控制器对数据库进行增删改操作
reducer 返回 nextState
将修改后的记录写回数据库
§ 最简单的例子 (
&!DOCTYPE html&
&script src=&///redux/3.5.2/redux.min.js&&&/script&
&/head&
/** Action Creators */
function inc() {
return { type: 'INCREMENT' };
function dec() {
return { type: 'DECREMENT' };
function reducer(state, action) {
// 首次调用本函数时设置初始 state
state = state || { counter: 0 };
switch (action.type) {
case 'INCREMENT':
return { counter: state.counter + 1 };
case 'DECREMENT':
return { counter: state.counter - 1 };
// 无论如何都返回一个 state
var store = Redux.createStore(reducer);
console.log( store.getState() ); // { counter: 0 }
store.dispatch(inc());
console.log( store.getState() ); // { counter: 1 }
store.dispatch(inc());
console.log( store.getState() ); // { counter: 2 }
store.dispatch(dec());
console.log( store.getState() ); // { counter: 1 }
&/script&
&/body&
&/html&
由上可知,Redux 并不一定要搭配 React 使用。Redux 纯粹只是一个状态管理库,几乎可以搭配任何框架使用
(上述例子连 jQuery 都没用哦亲)
写的太好了,我看官方的redux文档,看的云里雾里,这篇教程给了我很大的启发!
写的不错啊
CNode 社区为国内最专业的 Node.js 开源技术社区,致力于 Node.js 的技术研究。
服务器赞助商为
,存储赞助商为
,由提供应用性能服务。
新手搭建 Node.js 服务器,推荐使用无需备案的先贴一张redux的基本结构图
在这张图中,我们可以很清晰的看到,view中产生action,通过store.dispatch(action)将action交由reducer处理,最终根据处理的结果更新view。
在这个过程中,action是简单对象,用于描述一个动作以及对应于该动作的数据。例如:
const ADD_TODO = 'ADD_TODO';
type: ADD_TODO,
data: 'some data'
而reducer则是纯函数,且是幂等的,即只要传入参数相同,返回计算得到的下一个 state 就一定相同。没有特殊情况、没有副作用,没有 API 请求、没有变量修改,单纯执行计算。
同步数据流
在拥有了以上基本认知之后,我们来看下redux到底是如何工作的。Talk is cheap, show me the code.
import React from 'react'
import { createStore, bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import ReactDom from 'react-dom'
import { Provider } from 'react-redux'
function createAction() {
type: 'ADD_TODO',
data: 'some data'
class App ponent {
constructor() {
render() {
&div style={{width:'200px', height:'200px',margin:'100px',border:'2px solid black'}}&
&div onClick={this.props.actions.createAction.bind(this)}&
{&Click Me!&}
function mapStateToProps(state) {
data: state
function mapDispatchToProps(dispatch) {
actions: bindActionCreators({createAction}, dispatch)
var AppApp = connect(
mapStateToProps,
mapDispatchToProps
function reducer(state, action) {
console.log(action);
var store = createStore(reducer);
ReactDom.render(
&Provider store={store}&
&AppApp /&
&/Provider&,
document.getElementById('container')
这是一个精简版本的redux demo,每点击一次“Click Me!”,控制台会打印一次action。
由于篇幅限制,以上代码未分模块
下面是截图:
控制台打印输出:
从上面代码中可以清晰的看出,当用户点击“Click Me!”的时候,会立即调用createAction产生一个action,之后redux获取这个action并调用store.dispatch将这个action丢给reducer进行处理,demo中的reducer仅仅打印了action。
数据从view中流出,经reducer处理后又回到了view。
至此,我们看到的一切都是跟上面的基本认知是一致的。
接下来说说异步数据流,这块也是困扰了我好久,直到最近才搞清楚内在原因。
Redux Middleware
redux为我们做了很多的事情,我们都可以不用通过显示的调用dispatch函数就将我们的action传递给reducer。这在前面的demo中就可以看到。但是至此,redux一直没有解决异步的问题。试想,如果我在页面输入一段内容,然后触发了一个搜索动作,此时需要向服务端请求数据并将返回的数据展示出来。这是一个很常见的功能,但是涉及到异步请求,刚刚的demo中的方法已经不再适用了。那么redux是如何解决异步问题的呢?
没错,就是引入middleware。middleware,顾名思义就是中间件。用过express的同学对中间件应该都很熟悉。其实在redux中,middleware并不仅仅用于解决异步的问题,它还可以做很多其他的事情,比如记录日志、错误报告、路由等等。
关于redux middleware的说明在官方文档中已经有了非常清晰的说明,和都有,这里就不在赘述,只摘录一句话,说明如下。
It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer.
这里我想说下redux middleware的具体实现,我也正是从源代码中找到了困扰我的问题的原因。
先看applyMiddleware(...middlewares)的代码:
import compose from './compose'
export default function applyMiddleware(...middlewares) {
return (createStore) =& (reducer, initialState, enhancer) =& {
var store = createStore(reducer, initialState, enhancer)
var dispatch = store.dispatch
var chain = []
var middlewareAPI = {
getState: store.getState,
dispatch: (action) =& dispatch(action)
chain = middlewares.map(middleware =& middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
代码很短,此处我们只关注最内层函数的实现。在创建了store以后,我们对传进来的每一个middleware进行如下处理:
var middlewareAPI = {
getState: store.getState,
dispatch: (action) =& dispatch(action)
chain = middlewares.map(middleware =& middleware(middlewareAPI))
处理后得到一个数组保存在chain中。之后将chain传给compose,并将store.dispatch传给返回的函数。那么在这里面做了什么呢?我们再看compose的实现:
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg =& arg
const last = funcs[funcs.length - 1]
const rest = funcs.slice(0, -1)
return (...args) =& rest.reduceRight((composed, f) =& f(composed), last(...args))
compose中的核心动作就是将传进来的所有函数倒序(reduceRight)进行如下处理:
(composed, f) =& f(composed)
我们知道Array.prototype.reduceRight是从右向左累计计算的,会将上一次的计算结果作为本次计算的输入。再看看applyMiddleware中的调用代码:
dispatch = compose(...chain)(store.dispatch)
compose函数最终返回的函数被作为了dispatch函数,结合官方文档和代码,不难得出,中间件的定义形式为:
function middleware({dispatch, getState}) {
return function (next) {
return function (action) {
return next(action);
middleware = (dispatch, getState) =& next =& action =& {
next(action);
也就是说,redux的中间件是一个函数,该函数接收dispatch和getState作为参数,返回一个以dispatch为参数的函数,这个函数的返回值是接收action为参数的函数(可以看做另一个dispatch函数)。在中间件链中,以dispatch为参数的函数的返回值将作为下一个中间件(准确的说应该是返回值)的参数,下一个中间件将它的返回值接着往下一个中间件传递,最终实现了store.dispatch在中间件间的传递。
看了中间件的文档和代码之后,我算是搞明白了中间件的原理。之前一直困扰我的问题现在看来其实是概念问题(此处不提也罢),中间件只关注dispatch函数的传递,至于在传递的过程中干了什么中间件并不关心。
下面看看通过中间件,我们如何实现异步调用。这里就不得不提redux-thunk中间件了。
redux-thunk
redux与redux-thunk是同一个作者。
我们知道,异步调用什么时候返回前端是无法控制的。对于redux这条严密的数据流来说,如何才能做到异步呢。redux-thunk的基本思想就是通过函数来封装异步请求,也就是说在actionCreater中返回一个函数,在这个函数中进行异步调用。我们已经知道,redux中间件只关注dispatch函数的传递,而且redux也不关心dispatch函数的返回值,所以只需要让redux认识这个函数就可以了。
看了一下redux-thunk的源码:
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) =& next =& action =& {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
return next(action);
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkM
这段代码跟上面我们看到的中间件没有太大的差别,唯一一点就是对action做了一下如下判断:
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
也就是说,如果发现actionCreater传过来的action是一个函数的话,会执行一下这个函数,并以这个函数的返回值作为返回值。前面已经说过,redux对dispatch函数的返回值不是很关心,因此此处也就无所谓了。
这样的话,在我们的actionCreater中,我们就可以做任何的异步调用了,并且返回任何值也无所谓,所以我们可以使用promise了:
function actionCreate() {
return function (dispatch, getState) {
// 返回的函数体内自由实现。。。
Ajax.fetch({xxx}).then(function (json) {
dispatch(json);
通过redux-thunk,我们将异步的操作融合进了现有的数据流中。
最后还需要注意一点,由于中间件只关心dispatch的传递,并不限制你做其他的事情,因此我们最好将redux-thunk放到中间件列表的首位,防止其他中间件中返回异步请求。
以上是最近一段时间学习和思考的总结。在这期间发现,学习新知识的基础是要把概念理解清楚,不能一味的看样例跑demo,不理解概念对demo也只是知其然不知其所以然,很容易陷入一些通过样例代码理解出来的错误的概念中,后面再纠正就需要花费很多时间和精力了!
阅读(...) 评论()上周利用业余的时间看了看Redux,刚开始有点不适应,一下在有了Action、Reducer、Store和Middleware这么多新的概念。
经过一些了解之后,发现Redux的单向数据里的模式还是比较容易理解的,结合着Redux的单向数据流模型,很多概念就比较清晰了。
下面就按照自己的理解整理出了Redux中相关的内容,如果你也刚开始学习Redux,希望能给你一个直观的认识。
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) {
type: ADD_TASK,
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
return state
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联系在一起了:
Store通过dispatch(action)方法来接收不同的Action
根据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中常用的中间件:
:action可以是一个函数,用来发起异步请求。
:action可以是一个promise对象,用来更优雅的进行异步操作。
: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之间的通信,下面就分别看看这两个模块。
通过可以看到,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通过,可以将属性(props)直接给子孙component,无须通过props层层传递,从而减少组件的依赖关系。
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
&WrappedComponent {...this.nextState} /&
Connect.contextTypes = {
store: storeShape
详细内容和demo
文中很多Redux的概念都是进行了简单的介绍,更多详细的介绍可以参考我整理的内容,GitHub地址:
每篇文章的结尾都会有一些简单的,帮助理解文章中介绍的内容。
文中结合三张图片介绍了Redux中的一些核心概念,以及React和Redux之间通过react-redux这个库进行交互。
更多详细的内容,已经整理到了GitHub上了(),通过这些介绍以及demo的运行结果,一定能对Redux有一个比较基本的认识。
所有的内容主要参考,然后加上了自己的理解画了上面三张图,同时结合每个概念写了一些demo帮助理解。&
阅读(...) 评论()

我要回帖

更多关于 redux 异步请求 的文章

 

随机推荐