實習的時候,公司使用的是react,react說實話生態學的還不是很完善,就暫時先不做跟react相關的博客,等以后學好了react全家桶之后,專門再總結一下react的內容
這兩天看了公司的alita和dva,具體項目還沒上手,但是對dva很感興趣,一方面因為dva名字的由來,另一方面剛好在看redux的內容。
在講redux的時候,不得不把vuex拿出來講講,說實話,vuex很久之前學的了,vue是我前端框架第一次接觸的,vue的方便性也讓我很喜愛,但是身為一個前端攻城獅怎么能不學其他框架呢,趁着在公司實習的日子里,把react的學習提上日程
扯遠了,回到redux和vuex中。redux是一個狀態數據的管理庫,它可以用在react,也可以用在vue中,但是vue自己有一個vuex,兼容性更好,所以更大多數redux用在react的項目中。
學習vuex的時候,與現在的redux做對比,很清晰能比較出來,vuex比redux簡單
下圖是vuex的工作流程原理

VueX是數據管理框架,在之前我們vue里面的數據是data,父子組件,provide等等傳遞 在vue工程里面,數據就不是組件級別的創建,而是頁面級別的創建了
VueX創建了全局的倉庫,在vuex的state中,存放在全局的數據。我們使用vuex提供的store對象的state屬性,來獲取全局的數據
export default{ name:'Home', computed:{ myName(){ return this.$store.state.name; } } }
我們如何修改全局的數據?Vuex不允許我們直接修改全局的數據
因此我們要 調用$store里面一個方法叫做dispatch,他去派發一個action,這個action的名字叫做change 在createStore里就有一個action接收派發而來的change,執行這個change方法。在這個方法中提交一個commit觸發一個mutation,在mutations里面接收觸發而來方法並執行,在該方法中我們就可以修改數據
vuex的工作流程就是,組件之間使用dispatch去派發一個action,vuex中主要有三個屬性action,commit,state用來操作管理數據。
actions感知到組件所派發的action,執行action對應參數的方法,提交一個commit去觸發mutation,mutation中執行收到的commit的參數方法。從而修改state數據,而這個state數據就是全局的數據倉庫

在最近的學習中,我接觸到了redux,說實話,redux復雜程度高於vuex。
react整個應用中會存在很多個組件,每個組件的state是由自身進行管理,包括組件定義自身的state、組件之間的通信通過props傳遞、使用Context實現數據共享
將所有的狀態進行集中管理,當需要更新狀態的時候,僅需要對這個管理集中處理,而不用去關心狀態是如何分發到每一個組件內部的
redux就是一個實現上述集中管理的容器,遵循三大基本原則:
- 單一數據源
- state 是只讀的
- 使用純函數來執行修改
redux要求我們把數據都放在 store公共存儲空間
一個組件改變了 store 里的數據內容,其他組件就能感知到 store的變化,再來取數據,從而間接的實現了這些數據傳遞的功能
React Components (組件)需要獲取一些數據, 然后它就告知 Store 需要獲取數據,這就是 Action Creactor , Store 接收到之后去 Reducer 查一下, Reducer 會告訴 Store 應該給這個組件什么數據
如何使用?
創建一個store
import { createStore } from 'redux' // 引入redux
const store = createStore() // 創建數據的公共存儲區域
還需要創建一個記錄本去輔助管理數據,也就是reduecer,本質就是一個函數,接收兩個參數state,action,返回state
// 設置默認值 const initialState = { counter: 0 } const reducer = (state = initialState, action) => { }
將記錄本傳遞給store,兩者建立連接,獲取store里面的數據,則通過store.getState()來獲取當前state
const store = createStore(reducer)
store.getState()
那么如何更改store中的數據呢?
是通過dispatch來派發action,通常action中都會有type屬性,還有傳入的更改數據。
type屬性代表這個action所要做的操作
store.dispatch({ type: "ADD_NUMBER", number: 5 })
ruducer中處理所要進行操作,使用swich去接收不同action所代表的操作方法
const reducer = (state = initialState, action) => { switch (action.type) { case "INCREMENT": return {...state, counter: state.counter + 1}; case "DECREMENT": return {...state, counter: state.counter - 1}; case "ADD_NUMBER": return {...state, counter: state.counter + action.number} default: return state; } }
注意,reducer是一個純函數,不需要直接修改state
這樣派發action之后,既可以通過store.subscribe監聽store的變化,如下:
store.subscribe(() => {
console.log(store.getState());
})
小結
- createStore可以幫助創建 store
- store.dispatch 幫助派發 action , action 會傳遞給 store
- store.getState 這個方法可以幫助獲取 store 里邊所有的數據內容
- store.subscrible 方法訂閱 store 的改變,只要 store 發生改變, store.subscrible 這個函數接收的這個回調函數就會被執行
在React項目中,會搭配react-redux進行使用
何為react-redux?
如下圖

在react-redux中,我們將UI組件去除掉redux的操作,將redux的操作全部放在容器組件身上
容器組件向redux進行數據獲取和更改,通過props將數據傳遞給UI組件,UI組件也通過props告知容器組件要對redux中的數據進行何樣的操作
容器組件用以專門向reduxi請求修改狀態,存在containers文件夾里面
UI組件無法向redux去修改,存在component文件夾里面
connet是一個函數,這個函數調用的返回值依舊是一個函數 ,返回值的函數讓容器組件與UI組件進行關聯,從而通過props進行組件間的通信。
const CountContainer=connect()(CountUI)
connect在第一次調用的時候要傳入兩個參數,傳入的兩個參數必須是函數 一個是redux中所保存的狀態,另一個就是操作狀態的方法。簡寫如下
function a(){ return {n:900} } function b(){ return {jia:(num)=>{dispatch({
type: "ADD_NUMBER", number: 5
})}} } export default connect(a,b)(CountUI)
a函數返回的對象key作為UI組件的props的key,value作為UI組件的props的value,以供UI組件接收到state
b函數返回的對象實際上向redux派生一個action,告知redux對state中的數據進行何種操作
容器組件的兩個方法:mapStateToProps和mapDispatchToProps.
這是官方給的名稱,為了好理解上面的代碼使用a,b簡述。實際使用以官方文檔為主
export default connect(mapStateToProps,mapDispatchToProps)(CountUI)
回到今天所學習到的新框架——dva
dva 好像就是redux的一些輕量級應用整合,簡化了API,讓開發更方便,但果然這是我自己的理解。
核心概念
- State:一個對象,保存整個應用狀態
- View:React 組件構成的視圖層
- Action:一個對象,描述事件
- connect 方法:一個函數,綁定 State 到 View
- dispatch 方法:一個函數,發送 Action 到 State
不難發現,其本質和redux一樣,只不過dva讓redux的操作更加的方便簡潔,提高了我們的開發效率。
Action 是用來描述 UI 層事件的一個對象。
connect 方法返回的也是一個 React 組件,也是稱為容器組件。因為它是原始 UI 組件的容器,即在外面包了一層 State。
connect 方法傳入的第一個參數是 mapStateToProps 函數,mapStateToProps 函數會返回一個對象,用於建立 State 到 Props 的映射關系。
dispatch 是一個函數方法,用來將 Action 發送給 State。
dispatch 方法從哪里來?被 connect 的 Component 會自動在 props 中擁有 dispatch 方法。
其實dva內容和react-redux是一樣的原理,只不過為了開發速度,dva封裝的API使得操作redux更為便捷
dva中有model對象,這個對象是我第一次遇到的,在這個對象中,封裝這對redux中的各種操作
model最簡結構
export default { namespace: 'count', state: 0, reducers: { add(state) { return state + 1; }, }, effects: { *addAfter1Second(action, { call, put }) { yield call(delay, 1000); yield put({ type: 'add' }); }, }, };
Model 對象的屬性
- namespace: 當前 Model 的名稱。整個應用的 State,由多個小的 Model 的 State 以 namespace 為 key 合成
- state: 該 Model 當前的狀態。數據保存在這里,直接決定了視圖層的輸出
- reducers: Action 處理器,處理同步動作,用來算出最新的 State
- effects:Action 處理器,處理異步動作
Reducer
Reducer 是 Action 處理器,用來處理同步操作,可以看做是 state 的計算器。它的作用是根據 Action,從上一個 State 算出當前 State。
Effect
Action 處理器,處理異步動作,基於 Redux-saga 實現。Effect 指的是副作用。根據函數式編程,計算以外的操作都屬於 Effect,典型的就是 I/O 操作、數據庫讀寫。
Generator 函數
Effect 是一個 Generator 函數,內部使用 yield 關鍵字,標識每一步的操作(不管是異步或同步)。
call 和 put
dva 提供多個 effect 函數內部的處理函數,比較常用的是 call 和 put。
-
- call:執行異步函數
- put:發出一個 Action,類似於 dispatch
我們約定當 src/models 下存在 dva 的 models 文件時,會被自動加載到項目中。 即約定了存在即生效,因此我們約定僅在這個文件夾下存放 dva 的 models 文件,雖然存放其他的文件會被框架自動過濾忽略,但是在這個目錄存放其他文件會增加理解的心智負擔,建議不要存放無關的文件。且為了管理方便,一般將文件名和 models 的 namespace 一一對應,不僅可以直觀的找到相應的 models ,而且能夠保證不會存在 models 沖突的問題,因為文件系統本身就不允許同名文件。
時間不早,先休息,后面將會針對dva操作redux的具體進行總結,在這個總結中我們可以很直白的看出dva與redux操作上的簡易程度
宣傳下自己的網站mishi-blog.com
尚在襁褓中的一個網站。
