天天看點

Redux - javaScript狀态管理器在React中的運用

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:"我是清單内容"
});
           
Redux - javaScript狀态管理器在React中的運用

如圖,store的subscribe()方法在每次state修改時都會去監聽,控制台輸出了每次監聽到的修改的結果。