Redux
官方連結https://www.redux.org.cn/
Redux 是一個獨立的JavaScript 狀态管理庫,不屬于React内容。
Redux 本身是 MVVM漸進式架構 M(資料模型) - V(視圖) - VM(虛拟模型)
定義: 官方定義,是 JavaScript 狀态容器,提供可預測化的狀态管理。
作用及特點:
- 可以建構一緻化的應用,
- 運作于不同的環境(用戶端、伺服器、原生應用),
- 易于測試
- 提供超爽的開發體驗,比如有一個時間旅行調試器可以編輯後實時預覽。
- 除了與React一起用之外,還支援其它界面庫。
- 體小精悍(隻有2kB,包括依賴)。
Redux 三大原則
- 單一資料源: 整個應用的state 被儲存在一棵對象樹中,并且這個對象隻存在于唯一的store中
- State 是隻讀的,通過觸發 action去改變state(唯一方法),action是一個用于描述已發生事件的普通對象
- 使用純函數來進行修改
使用之前先安裝(通過npm來安裝)
store
負責存儲的倉庫
,是一個對象。
為了對 state, reducer, action,進行統一的管理和維護,
我們需要建立一個Store對象(倉庫)
import {createStore} from 'redux';
// createStore()建立一個倉庫,倉庫存儲state,reducer管理者管理state
// 注意該方法中傳入reducer函數體,不是函數的調用
let store = createStore(reducer);
console.log(store);
store對象提供的方法:
/*
* dispatch(action):發起一次修改(同步方法,會立即執行)
* --參數action
* action:{type:"做了什麼修改"}
*
* subscribe(listener):監聽狀态的修改(每次state有修改,都會監聽)
* getState():擷取狀态
* replaceReducer(nextReducer):替換掉reducer(不常用)
*
*/
state
資料存儲到一個對象樹中進行統一管理的位置成為state
注意
:為了保證資料狀态的可維護性和測試,不推薦直接修改state中的原資料,state是隻讀的。
修改 state
我們通過
純函數
來對state修改,什麼是純函數?
純函數是函數式程式設計的一種概念。
function reducer(state=預設值,action){return xx;}
第一個參數(必需):state的初始值(資料)
第二個參數(必需):action修改了什麼
return 傳回值(必需)
純函數特點如下:
- 相同的輸入永遠傳回相同的輸出
- 不修改函數的輸入值
- 不依賴外部環境狀态
- 無任何副作用 (如:異步請求以及定時器造成的問題)
使用純函數的好處:
- 便于測試
- 有利于重構
reducer
reducer如同管理者,去管理store倉庫中存儲的state
function reducer(state={
name:"React從初級到精通",
price:59
},action){
//action是dispatch方法傳過來的對象(即修改後的值傳回的新對象)
// switch做分類判斷
switch (action.type) {
// 修改的name
case 'new-name':
// 當 state 變化時需要傳回全新的對象,而不是修改傳入的參數。
return {
// 解構state
...state,
// name的新值
name:action.name
}
// 修改的price
case 'new-price':
return {
...state,
price:action.price
}
}
return state;
}
action
通過reducer 純函數來進行對state修改,同時通過傳入的 action 來執行具體的操作
- action 是一個對象
- type 屬性: 表示要進行操作的動作類型,如增删改查操作
- payload屬性: 操作 state 的同時傳入的資料
注意
:我們不直接去調用Reducer函數,而是通過Store對象提供的dispatch方法來調用
// 監聽state狀态
// 每次state修改都會觸發該監聽方法
store.subscribe(()=>{
console.log(store.getState())
});
// 修改state狀态
// 修改name
store.dispatch({
type:"new-name",
name:"HTML5全棧之路"
});
// 修改price
store.dispatch({
type:"new-price",
price:49
});
完整示例:
import React from 'react';
import {createStore} from 'redux';
function reducer(state={
// 首頁資料
index:{name:"首頁資料"},
// 留言資料
message:{name:"留言資料"},
// 清單資料
list:{name:"清單資料"}
},action){
switch (action.type) {
case "index":
return {...state,index:action.index.name}
case "message":
return {...state,message:action.message.name}
case "list":
return {...state,list:action.list.name}
}
return state;
}
let store = createStore(reducer);
store.dispatch({
type:"index_info",
name:"首頁"
})
store.dispatch({
type:"message_info",
name:"留言"
})
store.dispatch({
type:"list_info",
name:"清單"
})
function App() {
return (
<div className="App">
<h2>hello,good morning</h2>
</div>
);
}
export default App;
從上例中,我們看到如果有多個頁面需要管理時,都放在一個倉庫中,一個管理者去管理時,
代碼會顯得很臃腫不清晰,還有别的辦法可以處理嗎?
當然有,我們可以将它們分别封裝成函數,使用Redux提供combineRuders方法統一調用。
修改如下:
import {createStore,combineRuders} from 'redux';
//分别封裝成函數,分别管理,相當于使用分管理者去管理,最後再主管理者reducer通過分管理者去統一管理
function index(state={info:"首頁"},action){
switch (action.type) {
case "index_info":
return {
...state,
index:action.info
}
}
return state;
}
function message(state={info:"留言"},action){
switch (action.type) {
case "message_info":
return {
...state,
message:action.info
}
}
return state;
}
function list(state={info:"清單"},action){
switch (action.type) {
case "list_info":
return {
...state,
list:action.info
}
}
return state;
}
// 手動合并
//function reducer(state={},action){
// return {
// index:index(state.index,action),
// message:message(state.message,action),
// list:list(state.list,action)
// }
//}
// 使用Redux提供的combineReducers()方法來合并
let reducer = combineReducers({
// 給該方法傳入一個對象作為參數,這個對象的屬性就是要合并的reducer,
// 對象的屬性名:函數名
// 這裡的對象的屬性名與函數名一緻,隻寫一個就可以
index,
message,
list
});
// 建立倉庫
let store = createStore(reducer);
// 監聽state
store.subscribe(()=>{
console.log(store.getState());
});
// 修改state
store.dispatch({
type:"index_info",
info:"我是首頁内容"
});
store.dispatch({
type:"message_info",
info:"我是留言内容"
});
store.dispatch({
type:"list_info",
info:"我是清單内容"
});
如圖,store的subscribe()方法在每次state修改時都會去監聽,控制台輸出了每次監聽到的修改的結果。