簡單準備
- 通過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物件,當然這裡在處理非同步資料的時候需要返回一個函式,此時需要用到中介軟體去改寫dispatch。
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再計數完成啦。