在学习Redux以前,不妨先了解下Flux:javascript
一个基本的流程能够描述为html
与React关系能够理解为:前端
Flux:是一个系统架构,用于推动应用中的数据单向流动 React:是一个JavaScript库,用于构建“可预期”和“声明式”的可组合式Web用户界面
问题vue
参考java
Flux架构入门教程 - ryfeng;python
Flux For Stupid People;react
一篇漫画,图解Flux;git
Redux是基于Flux架构思想的一个库的实现,JavaScript状态容器,提供可预测化的状态管理。es6
设计思想github
三大原则
显著特色
核心元素
Redux中的 reducer 就是一个纯函数,store.dispatch(_action) 会自动触发 reducer 方法,更新state。
注意,reducer方法不会改变state,而是返回一个全新的state对象。
关于纯函数:一样的输入,一定获得一样的输出
Date.now()
或Math.random()
等不纯的方法,由于每次会获得不同的结果适用场景
多交互、多数据源
关于Redux的生态系统,请参见:http://www.redux.org.cn/docs/introduction/Ecosystem.html
store
本质:状态树
let { subscribe, dispatch, getState } = createStore(reducer);
关于createStore的基本实现,辅助理解
function createStore(reducer, initialState) { //闭包私有变量 var currentReducer = reducer; var currentState = initialState; var listeners = []; function getState() { return currentState; } function subscribe(listener) { listeners.push(listener); return function unsubscribe() { var index = listeners.indexOf(listener); listeners.splice(index, 1); }; } function dispatch(action) { currentState = currentReducer(currentState, action); listeners.slice().forEach(listener => listener()); return action; } //返回一个包含可访问闭包变量的公有方法 return {dispatch, subscribe, getState}; }
store能够看做是对reducer的封装,经过store.dispatch(action)自动触发对reducer的调用,而不是直接调用reducer(currentState, action),在必定程度上能够避免频繁传参,以更好地对store进行统一管理。
Action & Action Creator & bindActionCreators
var actionCreatorsNew = bindActionCreators(actionCreators, store.dispatch);
借鉴store对reducer的封装,对store.dispatch做封装,自动把actionCreators绑定到dispatch,使actionCreators成为具备操做全局state的函数集合。
其中,actionCreators表示action集合。触发action,会自动调用dispatch(action),避免直接对dispatch的调用。
middleware
异步场景:在异步操做结束后自动执行reducer
即,如何在操做结束时,自动送出第二个 Action
扩展点:dispatch()发出时,reducer()处理前
对于中间件,举例,日志中间件 redux-logger
import { applyMiddleware, createStore } from 'redux'; import createLogger from 'redux-logger'; const logger = createLogger(); const store = createStore(reducer, initial_state, applyMiddleware(logger) );
other,请注意中间件的引入次序。
给出 applymiddleware 的实现,仅供参考
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var store = createStore(reducer, preloadedState, 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); return {...store, dispatch} } }
其中,compose 用于组合函数、串联链式执行,顺序自右向左,维护扩展方便
var greeting = (firstName, lastName) => 'hello, ' + firstName + ' ' + lastName var toUpper = str => str.toUpperCase() var fn = compose(toUpper, greeting) console.log(fn('jack', 'smith')) // ‘HELLO,JACK SMITH’
异步状况,涉及发出三种不一样种类的 Action
同时,state须要维护、以反映不一样的操做状态
let state = { // ... isFetching: true, // 表示是否在抓取数据 didInvalidate: true, // 表示数据是否过期 lastUpdated: 'xxxxxxx' // 表示上一次更新时间 };
整个异步操做流程应该是这样的
在Redux中,中间件是纯粹的函数,有明确的使用方法而且严格的遵循如下格式:
var anyMiddleware = function ({ dispatch, getState }) { return function(next) { return function (action) { // 你的中间件业务相关代码 } } }
全部的这些,applyMiddleware会所有替咱们封装实现。
异步解决方案能够引入中间件 redux-thunk 或 redux-promise
可是,二者均是相对原始的解决方案,在action须要组合、取消时操做不易处理。最佳实践dva推荐 redux-saga,可测试、可mock、声明式的指令,管理actions,处理异步逻辑,管理全部的业务逻辑。
组件分类
Redux的重要思想就是:容器组件和展现组件的分离
业务逻辑:针对UI组件
在网上看到一个很是不错的关系图,分享给你们
connect
将 UI 组件生成容器组件:
const HocView = connect(mapStateToProps, mapDispatchToProps)(myComp)
其中,mapStateToProps
负责输入逻辑、将状态数据state映射到 UI 组件的参数props,mapDispatchToProps
负责输出逻辑、将用户对 UI 组件的操做映射成 Action。
mapStateToProps会订阅Store,每当state更新,就会自动执行,从新计算 UI 组件的参数,从而触发 UI 组件的从新渲染。
<Provider>
用来实现对store的全局访问,使容器组件获取到state:
render( <Provider store={store}> <Root /> </Provider>, document.getElementById('root') )
原理是利用React的 context 属性:
class Provider extends Component { getChildContext() { return { store: this.props.store }; } render() { return this.props.children; } } Provider.childContextTypes = { store: React.PropTypes.object }
子组件经过 this.context.store 获取。一个简单的计数器例子,供参见。
Redux扩展: redux-devtools-extension
使用步骤
redux-devtools-extension
包参考
Redux教程(1-4) - 阮一峰;Redux视频前30集;后30集;
redux在react中的应用(基础篇);redux入门教程;
看漫画,学Redux;redux 三重境 - 对 redux 最佳实践的思考和总结;
前面提到 redux-saga 能够做为 Redux 的异步解决方案,简单学习之,为后面学习 dva 做个铺垫。
A Redux middleware for handling side effects (异步任务).
Redux中间件,基于ES6的Generator功能,用于管理应用程序Side Effect的库,反作用例如
建议先了解下 Generator语法。经过redux-saga中间件将 Saga 与 Redux Store 创建链接:
import { createStore, applyMiddleware } from 'redux' import createSagaMiddleware from 'redux-saga' import reducer from './reducers' import mySaga from './sagas' const sagaMiddleware = createSagaMiddleware(); const store = createStore(reducer, applyMiddleware(sagaMiddleware)); sagaMiddleware.run(mySaga); /// then run the saga
其中,'./sagas' 用于处理全部异步操做逻辑,'./reducers' 用于处理action对stage更新。
参考
redux-saga | 中文教程; redux-saga-beginner-tutorial;
由支付宝前端团队开发,相关历史可参见:支付宝前端应用架构的发展和选择: 从 roof 到 redux 再到 dva
相关简介参见:dva - what&why -简介;
注意,dva 是 framework,而 redux 是 library。
最核心功能是提供 app.model 方法,用于把 reducer, initialState, action, saga 封装到一块儿
每一个路由对应一个model,这个model掌管该路由的全部状态(action、state、reducer、sagas),组件想改变状态只要dispatch type便可。
参考