上一篇介紹了 react-router串慰,今天介紹 redux。
什么是 Redux笙各?
現(xiàn)如今钉答,我們的項(xiàng)目都是由一個(gè)一個(gè)的模塊組成的,組件化的思想更適合大且復(fù)雜的項(xiàng)目杈抢。
在此之前数尿,React 并不適合寫大型應(yīng)用,因?yàn)樗?dāng)時(shí)還沒有很好地解決組件之間的通信問題惶楼。
為了解決這個(gè)問題右蹦,2014 年 Facebook 提出了 Flux 架構(gòu)的概念,引發(fā)了很多的實(shí)現(xiàn)歼捐。2015 年何陆,Redux 出現(xiàn),將 Flux 與函數(shù)式編程結(jié)合在一起豹储,很短時(shí)間內(nèi)就成為了最熱門的前端框架贷盲。
什么時(shí)候需要 Redux?
有人說過剥扣,挺有道理的哈巩剖。
如果你不知道是否需要 Redux铝穷,那就是不需要它。
在以下場景你可以考慮使用它:
- 組件間需要共享狀態(tài)
- 狀態(tài)需要在任何地方都能拿到
- 一個(gè)組件需要改變另一個(gè)組件的狀態(tài)
- 一個(gè)組件需要改變?nèi)譅顟B(tài)
*以上內(nèi)容引自阮一峰老師的博客佳魔,本教程是為了接入而接入曙聂,哈哈。
Redux 設(shè)計(jì)思想
- Web 應(yīng)用是一個(gè)狀態(tài)機(jī)吃引,View 與 State 是一一對應(yīng)的筹陵。
- 所有的狀態(tài),保存在一個(gè)對象里面镊尺。
基本概念和 API
先了解一下以下幾個(gè)概念吧
Store:保存數(shù)據(jù)的容器朦佩。由
Redux
提供的createStore
函數(shù)來生成唯一的Store
對象。State:
Store
對象包含的數(shù)據(jù)庐氮。當(dāng)前的狀態(tài)语稠,可通過store.getState()
獲取。Redux 規(guī)定一個(gè)State
對應(yīng)一個(gè)View
弄砍。Action:
View
發(fā)出的動(dòng)作(如用戶點(diǎn)擊鼠標(biāo)等行為)通知State
要發(fā)生改變仙畦。Action
是改變State
的唯一辦法。它是一個(gè)對象音婶,其中type
屬性是必須的慨畸,表示Action
的名稱,其他屬性可以自由設(shè)置衣式,其社區(qū)有一個(gè)規(guī)范可以參考寸士。如const action = { type: 'SOMETHING_TODO', payload: 'SOME DATA' }
。Action Creator:生成
Action
的函數(shù)碴卧。當(dāng)有若干Action
時(shí)弱卡,全部手寫可能略顯麻煩,可以定義一個(gè)函數(shù)來生成Action
住册,這種函數(shù)叫做Action Creator
婶博。store.dispatch():是
View
發(fā)出Action
的唯一方式。Reducer:當(dāng)
Store
收到Action
之后荧飞,必須返回一個(gè)新的State
凡人,這樣View
才會(huì)發(fā)生變化,這種State
的計(jì)算過程叫做Reducer
叹阔。它是一個(gè)純函數(shù)划栓。Pure Function:即純函數(shù),同樣的輸入条获,必定得到同樣的輸出忠荞,且沒有任何副作用
store.subscribe():監(jiān)聽
State
的變化,一旦State
發(fā)生變化,就自動(dòng)執(zhí)行這個(gè)函數(shù)委煤。它返回一個(gè)函數(shù)堂油,執(zhí)行該返回函數(shù)就解除監(jiān)聽。
實(shí)現(xiàn)最簡單的 Store 案例
先安裝 redux
依賴碧绞。
$ yarn add redux@4.0.4
在 src/js/store
目錄下新建一個(gè) index.js
文件府框。
// store/index.js
import { createStore } from 'redux'
// Reducer 處理函數(shù)
const reducer = (prevState, action) => {
const { type, payload } = action
switch (type) {
case 'ADD':
// 一定要不能修改 state,而是返回一個(gè)新的副本
// 倘若 state 是引用數(shù)據(jù)類型讥邻,一定要借助 Object.assign迫靖、對象展開運(yùn)算符(...)、其他庫的拷貝方法或者自己實(shí)現(xiàn)深拷貝方法兴使,返回一個(gè)新副本
return prevState + payload
case 'SUB':
return prevState - payload
default:
// default 或者未知 action 時(shí)系宜,返回舊的 state
return prevState
}
}
// 初始值
const initialState = 0
// 創(chuàng)建 Store(也可以不傳入 initialState 參數(shù),而將 reducer 中的 state 設(shè)置一個(gè)初始值)
const store = createStore(reducer, initialState)
// 監(jiān)聽 state 變化
// const unsubscribe = store.subscribe(() => {
// console.log('監(jiān)聽 state 變化', store.getState())
// })
// 解除監(jiān)聽
// unsubscribe()
export default store
我們在 Home 組件引入 Store发魄,并修改成:
// pages/home/index.js
import React, { Component } from 'react'
import store from '../../store'
class Home extends Component {
constructor(props) {
super(props)
this.state = {}
}
// Action Creator 函數(shù)
actionCreator(type, payload) {
return { type, payload }
}
handle(type, val) {
// 創(chuàng)建 Action
const action = this.actionCreator(type, val)
// 派發(fā) Action
store.dispatch(action)
// 獲取 State 快照
console.log(`當(dāng)前操作是 ${type}盹牧,State 為:${store.getState()}`)
}
render() {
return (
<div>
<h3>Home Component!</h3>
<button onClick={this.handle.bind(this, 'ADD', 1)}>加一</button>
<button onClick={this.handle.bind(this, 'SUB', 1)}>減一</button>
</div>
)
}
}
export default Home
上面案例,我們做了一個(gè)很簡單的加減操作励幼。
通過 redux
提供的 createStore
函數(shù)創(chuàng)建了唯一的一個(gè) store
對象汰寓,該函數(shù)接收三個(gè)參數(shù) createStore(reducer, [preloadedState], enhancer)
,其中第一第二個(gè)分別是 reducer
函數(shù)和初始值苹粟,第三個(gè)一般是使用中間件時(shí)用到有滑,我們后面會(huì)用到,這里暫不展開探討嵌削。(點(diǎn)這里了解更多)
Reducer
函數(shù)接收兩個(gè)參數(shù) reducer(state, action)
毛好,分別是 previousState(舊狀態(tài)) 和 Action。在首次執(zhí)行 state
為 undefined
掷贾,可以為它設(shè)置一個(gè)初始值,或者在 createStore
中傳入荣茫。它有點(diǎn)類似 Array.prototype.reduce()想帅。
借助我們在 Home
組件下引入 store
,并添加兩個(gè)按鈕啡莉,對 store
的 state
做加減操作港准。
至此
我們最簡單 redux 案例實(shí)現(xiàn)了,但是這個(gè)距離我們想要的咧欣,還不夠哦浅缸。
在此拋出幾個(gè)問題:
- 如何接入我們的 Component 了,當(dāng) state 發(fā)生變化時(shí)魄咕,使其自動(dòng)更新 View衩椒?
- 組件如何共享 Store?
- 如何查看 State 的變化?
下文繼續(xù)毛萌,未完待續(xù)…