@(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源碼的一些心得,以及各功能模塊的實現原理~