一個被寫爛的redux計數小例子
- 通過create-react-app快速搭建react專案
- 安裝依賴npm install redux react-redux redux-thunk --save (redux-thunk是處理非同步資料流的中介軟體)
- 更改,新建專案目錄

- 效果圖
Demo開始
編寫redux相關內容
action
export const Increment = 'increment' export const Decrement = 'decrement' /*action creator action建構函式*/ export const increment = (counterIndex) => { type:Increment, counterIndex } export const decrement = (counterIndex) => ({ type: Decrement, counterIndex }) 複製程式碼
Action 本質上是 JavaScript 普通物件。action 內必須使用一個字串型別的 type 欄位來表示將要執行的動作,但是這樣有多少action就需要寫多少action,所以這裡需要action creator, 這個action建構函式返回一個js物件,當然這裡在處理非同步資料的時候需要返回一個函式,此時需要用到中介軟體。
reducer
import { Increment, Decrement } from '../Action' export default (state,action) => { const {counterIndex} = action switch (action.type) { case Increment: return {...state, [counterIndex]:state[counterIndex]+1} case Decrement: return {...state, [counterIndex]:state[counterIndex]-1} default: return state } } 複製程式碼
reducer具體定義可以看redux自述中的定義,由於demo太簡單,拆分合並reducer大家自己看吧,這裡主要介紹redux在react中的工作流程。 這裡要注意reducer是個純函式,不能更改state,這裡返回的新state可以使用Object.assign 以及 es6的物件擴充套件符。
store
import {applyMiddleware, createStore} from 'redux' import thunk from 'redux-thunk' import reducer from '../Reducer' const initValue={ 'First':1, 'Second':5, 'Third':6 } const store=createStore(reducer,initValue) export default store 複製程式碼
createStorestore 可以接受一個初始的state,這裡可以設定服務端同構應用的初始化props。 至此redux的相關就結束,下面寫ui元件。
編寫UI元件
如果不用react-redux自動生成容器元件,元件劃分就要有容器元件和展示的區分,我理解的展示元件就是沒有自己的state,只接受 props決定UI該如何展示,所有的邏輯都在容器元件進行,由於react-redux,我們不需要自己寫容器元件
Counter
import React, { Component } from 'react'; import {increment, decrement} from '../Redux/Action' import {connect} from 'react-redux' import '../style/App.css'; const buttonMargin= { margin: "20px" } function Counter({index, Increment, Decrement, value}){ return ( <div> <button style={buttonMargin} onClick={Increment}>+</button> <button style={buttonMargin} onClick={Decrement}>-</button> <span>{index} count :{value}</span> </div> ) } function mapStateToProps(state,ownProps){ return{ value:state[ownProps.index] } } function mapDispatchToProps(dispatch, ownProps){ return{ Increment:() => { dispatch(increment(ownProps.index)) }, Decrement:() => { dispatch(decrement(ownProps.index)) } } } export default connect(mapStateToProps, mapDispatchToProps)(Counter); 複製程式碼
- react-redux提供方法connect()和元件,這裡說下connect(),引用阮一峰大神的總結: connect方法接受兩個引數:mapStateToProps和mapDispatchToProps。它們定義了 UI 元件的業務邏輯。前者負責輸入邏輯,即將state對映到 UI 元件的引數(props),後者負責輸出邏輯,即將使用者對 UI 元件的操作對映成 Action。
- mapStateToProps:作為函式,mapStateToProps執行後應該返回一個物件,裡面的每一個鍵值對就是一個對映。 接受兩個引數state,ownProps,state 。state更新的時候,就會自動執行,重新計算 UI 元件的引數,從而觸發 UI 元件的重新渲染,ownProps代表容器元件的props物件,如果容器元件的引數發生變化,也會引發 UI 元件重新渲染,例如上面個的計數;
- mapDispatchToProps是connect函式的第二個引數,用來建立 UI 元件的引數到store.dispatch方法的對映。也就是說,它定義了哪些使用者的操作應該當作 Action,傳給 Store。它可以是一個函式,也可以是一個物件
Panel
import React, { Component } from 'react' import Counter from './Counter.js' const style = { margin: "20px" } class Panel extends Component { render() { return ( <div style={style}> <Counter index="First" /> <Counter index="Second"/> <Counter index="Third" /> <hr/> </div> ) } } 複製程式碼
export default Panel
這裡就是個list。
index.js(入口檔案)
import React from 'react'; import ReactDOM from 'react-dom'; import './style/index.css'; import Panel from './Component/Panel'; import {Provider} from 'react-redux'; import store from './Redux/Store/store.js' import registerServiceWorker from './registerServiceWorker'; ReactDOM.render( <Provider store={store}> <Panel/> </Provider>,<pre> document.getElementById('root') ); registerServiceWorker(); 複製程式碼
React-Redux 提供Provider元件,可以讓容器元件拿到state,避免一層層向下傳,原理是context,其實也很好理解,vue有個bus。 至此一個同步的redux處理資料的demo就完成了,下面來說非同步。
非同步
vuex 提交的是Mutation(有點像git) 這個東西是同步, 而它有action 這裡可以同步非同步,但redux並沒有,所以這裡就有了中介軟體的出現,用於解決非同步action,中介軟體有幾種常用的,這裡只簡單寫下redux-thunk。 action creator 原則是返回一個js物件,非同步在這裡處理,返回的是一個函式,這就需要中介軟體的處理。 修改這兩處:
action:
export const Increment = 'increment' export const Decrement = 'decrement' export const increment = (counterIndex) => { return dispatch => { let asyncAct = { type:Increment, counterIndex } setTimeout(()=>{ //兩秒鐘之後再發送action dispatch(asyncAct); }, 2000) } } export const decrement = (counterIndex) => ({ type: Decrement, counterIndex }) 複製程式碼
store:
import {applyMiddleware, createStore} from 'redux' import thunk from 'redux-thunk' import reducer from '../Reducer' const initValue={ 'First':1, 'Second':5, 'Third':6 } const store=createStore(reducer,initValue,applyMiddleware(thunk)) //使用中介軟體的寫法applyMiddleware,如果多個,注意裡面中介軟體的順序 export default store 複製程式碼
簡單的延時2s再計數完成啦。