@(blog)react
本文的读者为了解flux概念,熟悉react,了解es6语法的同窗git
redux
是最近很火的一个 flux
框架,短短的一个月如今已经有2900+的 star 了,watch以后天天收到几百封 pr 的邮件,废话就很少说了。
为何要用 redux
,请看链接 The Evolution of Flux Frameworks。程序员
主要特色es6
browserify
,好处感受并不明显。store
中的数据不受限制,能够是 number
object
array
等等,废话,由于它的 store
只是简单的函数。devtools
,监控 action
的触发以及 state
的变化。api
很精简,不用记茫茫多的 api
connecter
与 provider
这两个东西用起来总以为很繁琐,不那么优雅。下面经过写的一个简单counter的例子 介绍 redux
的核心方法以及一些须要注意的地方。github
代码放在https://github.com/yeatszhang/redux-tutorial, 须要安装gulp编程
代码是基于分支 v1.0.0-rc
api略微有些区别,详情见 Breaking API changes for 1.0。redux
actions creator 是用来生成 action 的函数,在默认状况下能够接受返回object
或者function
的函数,不少人学习flux的时候把action与actionCreator弄混淆....:gulp
// 直接返回object actionCreators.addTodo = function(text) { return { type: types.ADD_TODO, text }; } // 返回函数 actionCreators.incrementAsync = function() { return (dispatch, getState) => { // actionCreator中能够经过getState得到当前的state console.log(getState()); // 异步action setTimeout(() => { dispatch({ type: INCREMENT_COUNTER2, }); }, 1000); }; };
在没有使用任何 middleware
的状况下,只有这有两种 action
能够被 dispatch
。api
在动态内容的最外层应该使用Provider进行包裹,provider接收store做为参数,注意children是一个函数
并非reactElement
。provider
将store做为context往子节点进行传递,并实现store
的热替换。所以在provider内的组件其实能够不经过connect来拿到dispatch以及state,而直接经过context拿到store对象,不过做者不推荐这么作。app
import React from 'react'; import { createStore, applyMiddleware, combineReducers } from 'redux'; // redux midlleware repositories import thunk from 'redux-thunk'; // 将 redux 与 react 相关的部分,如 connector provider 单独抽取出来 import { Provider } from 'react-redux'; import reducers from '../reducers'; import CounterApp from './CounterApp.js'; import logMiddleware from '../middleWares/logMiddleware.js'; const reducer = combineReducers(reducers); const createStoreWithMiddleware = applyMiddleware(thunk, logMiddleware)(createStore); const store = createStoreWithMiddleware(reducer); // 使用middleWare thunk, 若是没有自定义中间层的需求能够直接写 // const store = createStore(reducer); class App extends React.Component { render() { return ( <Provider store={store}> {() => <CounterApp />} </Provider> ); } }
smart component拥有两个特色:
刚接触redux的同窗确定会以为这个connect很难以理解。仍是在代码里面说把。。。
/** * Created by yichizhang on 15/7/26. */ import React, { Component } from 'react'; import { bindActionCreators } from 'redux'; import { Connector } from 'react-redux'; import Counter from '../components/Counter'; import actionCreators1 from '../actionCreators/actionCreators1.js'; import actionCreators2 from '../actionCreators/actionCreators2.js'; // state 是各reducer中state的集合 function select(state) { // 从各reducer中挑选出component须要监听的state return { counter1: state.reducer1.counter, counter2: state.reducer2.counter, }; } export default class CounterApp extends Component { // select函数的返回值会与dispatch组装程一个object做为参数 // 从这里看出connector就是帮忙拿到provider中store的dispatch方法以及挑选出须要使用的state renderChild({ counter1, counter2, dispatch}) { // 我的以为这样使用action十分不方便,尤为是当组件只须要触发actions不须要监听store的变化的时候。我会偷懒经过context去拿到dispatch~~ const actions1 = bindActionCreators(actionCreators1, dispatch); const actions2 = bindActionCreators(actionCreators2, dispatch); const props = { ...actions1, ...actions2, counter1, counter2 }; // 全部的action以及state都会以props的形式提供给Counter,而后在Counter里面就能够随心所欲了~ return <Counter {...props} />; } render() { return ( <Connector select={select}> {this.renderChild} </Connector> ); } }
redux认为程序员不须要去写store中的逻辑而只须要写明对state的处理逻辑就好:
old sate => action => new state
这是一个彻底同步的过程。reducer只须要声明初始状态以及state在接收到action以后的改变规则就能够了。
import React from 'react/addons'; import {INCREMENT_COUNTER1, DECREMENT_COUNTER1} from '../constants/actionsTypes.js'; const update = React.addons.update; // state能够是任何类型 const initialState = { counter: 0, }; // reducer只是一个简单的switch方法 export default function counter(state = initialState, action = null) { switch (action.type) { case INCREMENT_COUNTER1: // 须要注意的是connector当select中的state发生变化时会作一个shallow equal的操做, // 因此若是须要操做引用值的时候必定不能直接赋值,须要使用addon中的update或者immutable.js,知道看到这两个工具又不想继续学了..其实很简单 // 这样能够大大避免重复的render,从而提升性能 return update(state, { counter: { $set: state.counter + 1, }, }); case DECREMENT_COUNTER1: return update(state, { counter: { $set: state.counter - 1, }, }); default: return state; } }
感兴趣的同窗能够看看,通常来讲默认的thunk就够用了。我在例子里加了个log的中间层
// 打印触发的action function logMiddleware() { // 这里的next是下一个middleWare return function(next) { return function(action) { // 打印此action并使用下一个middleWare处理该action console.log(action); next(action); }; }; } export default logMiddleware; // 下面是默认的thunk middleWare function thunkMiddleware(_ref) { var dispatch = _ref.dispatch; var getState = _ref.getState; return function (next) { return function (action) { // 若是是函数则将dispatch与getState做为参数执行函数,不然交给写一个middleware处理 return typeof action === 'function' ? action(dispatch, getState) : next(action); }; }; }
其实redux不明白的地方直接看源码更好,redux的代码量很小并且组织也很清晰,建议你们都去看,不过做者貌似函数式编程的思惟很重,大量使用修饰器的语法,还有reduce~ 挺绕的~
以后会总结本身阅读redux源码的一些心得,以及各功能模块的实现原理~