上一篇我們學(xué)習(xí)了構(gòu)建一個(gè)react項(xiàng)目以及配置webpack并運(yùn)行項(xiàng)目,這篇我們?cè)谝雛edux之前學(xué)習(xí)它的運(yùn)行機(jī)制及設(shè)計(jì)思路。
Redux的架構(gòu)思想
1. state和store 的概念
state是React中定義的應(yīng)用狀態(tài),本質(zhì)是一個(gè)數(shù)據(jù)集的普通對(duì)象,例如
/** 應(yīng)用初始state **/
{
status: 0,
todos: []
}
store是應(yīng)用狀態(tài)state的管理者,包含四個(gè)函數(shù):
getState() #獲取整個(gè)state
dispatch(action) #觸發(fā)state改變的唯一途徑
subscribe(listener) #可以理解為DOM中的addEventListener
replayceReducer(nextReducer) #一般在Webpack按需加載的時(shí)候用
二者的關(guān)系 state = store.getState()
Redux規(guī)定:一個(gè)應(yīng)用只應(yīng)有一個(gè)單一的store,其管理著唯一的應(yīng)用狀態(tài)state且不能直接被修改,若要改變state,必須執(zhí)行dispatch一個(gè)action,這是修改應(yīng)用狀態(tài)的唯一方法。
現(xiàn)在您只需要記住action只是一個(gè)包含type屬性的普通對(duì)象即可
例如{type:'INCREMENT'}
我們知道了state是通過(guò)store.getState()獲取的,那么store是怎么來(lái)的呢?那就需要用到了Redux定義的createStore方法了。
import { createStore } from 'redux'
...
//store是將reducer傳入生成的
const store = createStore(reducer, initialState)
現(xiàn)在您只需要記住reducer是一個(gè)函數(shù),負(fù)責(zé)更新并返回一個(gè)新的state,而initialState主要用于前后端同構(gòu)的數(shù)據(jù)同步(詳情請(qǐng)關(guān)注React服務(wù)端渲染)
2. reducer
這里我們又要用到Redux中定義的另外一個(gè)方法combineReducers。
import { combineReducers } from 'redux'
...
const rootReducer = combineReducers({
captchaData,
loginState,
status,
userInfo
})
export default rootReducer
具體工作原理是dispatch執(zhí)行action之后,reducer負(fù)責(zé)根據(jù)action的type屬性重新將對(duì)應(yīng)action的payload值賦給nextState
3.Action
上面我們提到了action實(shí)質(zhì)的包含type屬性的普通對(duì)象,這個(gè)type是實(shí)現(xiàn)用戶行為的關(guān)鍵。例如我們?cè)黾右粋€(gè)支出分類
{
type: 'ADD_CATEGORY',
payload: {
id:1,
content:'交通'
}
}
當(dāng)然,action可以根據(jù)具體的業(yè)務(wù)來(lái)自由設(shè)定,唯一的必要屬性就是type,甚至我們可以寫(xiě)一個(gè)只包含type屬性的action
下面的action都是合法的
{
type: 'ADD_CATEGORY',
id:1,
content:'交通'
}
{
tyep: 'ADD_CATEGORY',
aabbcc: {
id: 1,
content: '交通'
}
}
{
type: 'ADD_CATEGORY'
}
雖然沒(méi)有約束,但最好還是遵循規(guī)范
這里有一個(gè)思考問(wèn)題,action難道就只是包含type等一些屬性的對(duì)象嗎?這里留一個(gè)懸念,后面我在具體用Redux的過(guò)程中再講。
Redux優(yōu)缺點(diǎn)
Action Creator => action => store.dispatch(action) => reducer(state, action) =>
原statestate = nextState
優(yōu)點(diǎn):清晰的數(shù)據(jù)流向,讓我們處理復(fù)雜的業(yè)務(wù)邏輯,可以更加方便的梳理業(yè)務(wù)線,action只負(fù)責(zé)執(zhí)行邏輯操作和數(shù)據(jù)獲取,reducer只負(fù)責(zé)返回?cái)?shù)據(jù)集,然后connect給react中的組件使用,讓react只關(guān)心交互界面的邏輯,無(wú)需關(guān)心數(shù)據(jù)邏輯。
另外我們使用redux還有如下好處
- 方便地能夠?qū)?yīng)用狀態(tài)存儲(chǔ)到本地并且重啟動(dòng)時(shí)能夠讀取恢復(fù)狀態(tài)
- 方便地能夠在服務(wù)端完成初始狀態(tài)設(shè)置,并且完成狀態(tài)的服務(wù)端渲染
- 能夠序列化記錄用戶操作,能夠設(shè)置狀態(tài)快照,從而方便進(jìn)行Bug報(bào)告與開(kāi)發(fā)者的錯(cuò)誤重現(xiàn)
- 能夠?qū)⒂脩舻牟僮骰蛘呤录鬟f給其他環(huán)境而不需要修改現(xiàn)有代碼
- 能夠添加重放或者撤銷功能而不需要重構(gòu)代碼
- 能夠在開(kāi)發(fā)過(guò)程中實(shí)現(xiàn)狀態(tài)歷史的回溯,或者根據(jù)Action的歷史重現(xiàn)狀態(tài)
- 能夠?yàn)殚_(kāi)發(fā)者提供全面透徹的審視和修改現(xiàn)有開(kāi)發(fā)工具的接口,從而保證產(chǎn)品的開(kāi)發(fā)者能夠根據(jù)他們自己的應(yīng)用需求打造專門的工具
- 能夠在復(fù)用現(xiàn)在大部分業(yè)務(wù)邏輯的基礎(chǔ)上構(gòu)造不同的界面
使用Redux我們必須遵循Redux的守則
- 必須使用基本對(duì)象與數(shù)組來(lái)描述應(yīng)用狀態(tài)
- 必須使用基本的對(duì)象來(lái)描述系統(tǒng)變化
- 必須使用純函數(shù)來(lái)處理系統(tǒng)中的業(yè)務(wù)邏輯
缺點(diǎn):由于必須遵守Redux的守則,即使很簡(jiǎn)單的業(yè)務(wù)邏輯,我們也必須有store,reducer,action.type。這樣給人的感覺(jué)就是殺雞用牛刀,所以對(duì)于簡(jiǎn)單的業(yè)務(wù)邏輯,我們無(wú)需引用Redux庫(kù)。
最后,Redux真正的靈魂在于其設(shè)計(jì)思想,很多時(shí)候并不一定需要引用Redux庫(kù)本身,但可以嘗試使用redux的思想。
import React, { Component } from 'react'
class Counter extends Component {
state = { value: 0 }
increment = () => {
this.setState(prevState => ({
value: prevState.value + 1
}))
}
decrement = () => {
this.setState(prevState => ({
value: prevState.value - 1
}))
}
render() {
return (
<div>
{this.state.value}
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
</div>
)
}
使用redux,我們可能會(huì)有禁用Local State的習(xí)慣,其實(shí)Local State有時(shí)候恰恰是用最簡(jiǎn)單的方法幫我們解決問(wèn)題。我們對(duì)上面代碼用redux思想進(jìn)行改造
import React, { Component } from 'react'
const counter = (state = { value:0 }, action) => {
switch (action.type) {
case 'INCREMENT':
return { value: state.value + 1}
case 'DECREMENT':
return { value: state.value - 1}
default:
return state
}
}
class Counter extends Component {
state = counter(undefined, {})
dispatch(action) {
this.setState(prevState => counter(prevState, action))
}
increment = () => {
this.dispatch({type: 'INCREMENT'})
}
decrement = () => {
this.dispatch({type: 'DECREMENT'})
}
render() {
return (
<div>
{this.state.value}
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
</div>
)
}
}
總結(jié)
- store由Redux的 createStore(reducer) 生成
- state通過(guò)store.getState()獲取,本質(zhì)是一個(gè)存儲(chǔ)整個(gè)應(yīng)用狀態(tài)數(shù)據(jù)集的對(duì)象
- reducer用于更新state并返回nextState的函數(shù),且reducer必須有返回值,否則nextState將為undefined
- action是一個(gè)包含type屬性的普通對(duì)象,用于dipatch來(lái)改變state
這一篇我們理解了Redux的幾個(gè)概念以及設(shè)計(jì)思想,下一篇我們要在項(xiàng)目中引用Redux庫(kù)并學(xué)習(xí)怎么使用它。