React — Redux詳解

萬事順意發表於2024-03-07

Redux 是一個用於 JavaScript 應用程式的狀態管理庫。它可以幫助您管理應用程式中的狀態,並確保狀態的一致性和可預測性。

Redux 主要用於處理大型應用程式中的複雜狀態邏輯,例如跨元件共享狀態、處理非同步資料流等。

Redux 的核心概念包括:

  1. Store(儲存):Redux 應用程式的狀態(state)被統一儲存在一個稱為 Store 的物件中。這個狀態是隻讀的,唯一改變狀態的方式是透過分發(dispatching)一個 action。

  2. Action(動作):Action 是描述發生了什麼事情的純 JavaScript 物件。它必須包含一個 type 屬性來指明動作的型別,通常還會包含一些與動作相關的資料。

  3. Reducer(歸納器):Reducer 是一個純函式,接收先前的狀態和一個 action,並返回新的狀態。Reducer 負責根據 action 更新應用程式的狀態。

  4. Dispatch(分發):使用 store.dispatch(action) 方法來分發一個 action,這是唯一能改變狀態的方法。

  5. Selector(選擇器):選擇器用於從 Store 中提取部分狀態資料,以便在應用程式的元件中使用。

Redux 的工作流程是:當應用程式中的某個地方發生了變化,比如使用者互動或者網路請求返回資料,就會建立一個對應的 action 並被分發到 store 中。然後,相應的 reducer 會根據 action 更新 store 中的狀態。最後,React 元件可以訂閱 store 中的狀態,並根據狀態的變化來更新介面。

透過這種方式,Redux 提供了一種可預測且一致的狀態管理機制,使得應用程式的狀態變化變得容易追蹤和除錯。這使得 Redux 成為處理大型複雜應用程式狀態的理想選擇。

一、CDN引入JS使用Redux

1.定義一個reducer函式(根據當前想要做的修改返回一個新的狀態)

2.使用createStore方法傳入reducer函式 生成一個store例項物件

3.使用store例項的subscribe訂閱資料的變化(資料一旦變化,可以得到通知)

4.使用store例項的dispatch方法提交action物件觸發資料變化(告訴reducer你想怎麼改資料)(修改資料的唯一方式)

5.使用store例項的getState方法獲取最新的狀態資料更新到檢視中

<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.1.1/redux.min.js"></script>
<div class="sum">
        <button id="reduce">
            -
        </button>
        <span id="num">
            0
        </span>
        <button id="add">
            +
        </button>
    </div>
<script>
    //1.定義reducer函式 : 根據不用的action函式,返回不同的state
    //state:管理資料的初始狀態
    //action:物件 type 標記當前想做什麼樣的修改
    function reducer(state={count:0},action){
    //資料不可變,基於原始狀態生成新的狀態
        if(action.type === 'INCREMENT'){
            return {count:state.count+1}
        }
        if(action.type === 'DECREMENT'){
            return {count:state.count-1}
        }
        return state
    }
    //2.使用createStore方法傳入reducer函式 生成一個store例項物件
    const store = Redux.createStore(reducer)
    //3.透過store例項的subscribe訂閱資料變化
    store.subscribe(()=>{
        console.log('state變化了',store.getState())
        document.getElementById('num').innerText=store.getState().count
    })
    //4.使用store例項的dispatch方法提交action物件觸發資料變化
    const inBtn = document.getElementById('add')
    const dBtn = document.getElementById('reduce')
    inBtn.addEventListener('click',()=>{
        store.dispatch({
            type:'INCREMENT'
        })
    })
    dBtn.addEventListener('click',()=>{
        store.dispatch({
            type:'DECREMENT'
        })
    })
</script>

二、creatReactApp(框架)使用Redux

1.建立環境

npm i @reduxjs/toolkit react-redux

(1) Redux Toolkit(RTK) 官方推薦編寫Redux邏輯的方式,是一套工具的集合集,簡化書寫方式

(2)react-redux 用來連結Redux和React元件的中介軟體

(3)目錄結構設計

2.使用方式

(1)配置子模組(子store)

import {createSlice} from "@reduxjs/toolkit"
//createSlice 建立store的方法
const countStore = createSlice({
    name : 'counter', //給模組一個名字
    initialState:{
        count : 0
    }, //初始化state
    reducers :{
        add(state){
            state.count++
        },
        reduce(state){
            state.count--
        },
    }//修改狀態的方法 同步方法 支援直接修改
})

//解構出來actionCreater函式==》解構出來的方法叫做actionCreater (也就是說這些方法是生成action物件的)
const {add,reduce} = countStore.actions

//獲取reducer函式
const reducer = countStore.reducer
//匯出建立action物件的函式和reducer函式
export {add,reduce,addNum}
export default reducer

(2)index.js入口檔案配置根store並組合子store

import {configureStore} from "@reduxjs/toolkit" //組合子模組的方法
import countReducer from './modules/counterStore' //匯入子模組


//配置
const store=configureStore({
    reducer:{
        counter : countReducer,
    }
})

//匯出
export default store

(3)在react中注入store

import store from './store/index'
import {Provider} from 'react-redux' 
//react-redux負責把Redux和React連線起來,內建Provider元件透過store引數把建立好的store例項注入到應用中,連結正式建立

//把App根元件渲染到id為root的dom節點
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

(4)使用store中的資料 修改store中的資料

import { useSelector,useDispatch } from 'react-redux';
//在React元件中使用store的資料,需要用到一個鉤子函式useSelector,他的作用是把store中的資料對映到元件中

import {add,reduce} from './store/modules/counterStore'
//匯入actionCreater
function App(){
const {count} = useSelector(state=>state.counter) const dispatch = useDispatch() //React元件中修改store中的資料需要藉助另一個hook函式 useDispatch ,他的作用是生成提交action物件的dispatch函式 return <div> <div> <button onClick={()=>{ dispatch(reduce()) }}>-</button> <span>{count}</span> <button onClick={()=>{ dispatch(add()) }}>+</button> </div> </div> }

(5)總結

元件中使用useSelector (hook函式)獲取store中的物件

元件中使用useDispatch(hook函式)獲取dispatch方法

執行store模組中匯出的actionCreater方法就能得到要提交的action物件

3.action傳參

(1)在reducer的同步修改方法中新增action物件引數

const countStore = createSlice({
    name : 'counter', //給模組一個名字
    initialState:{
        count : 0
    }, //初始化state
    reducers :{
        add(state){
            state.count++
        },
        reduce(state){
            state.count--
        },
        addNum(state,action){
            state.count= state.count+action.payload
        //引數會被傳遞到action物件的payload屬性上
        } //在reducer的同步修改方法中新增action物件引數
    }//修改狀態的方法 同步方法 支援直接修改
})

//解構出來actionCreater函式==》解構出來的方法叫做actionCreater (也就是說這些方法是生成action物件的)
const {add,reduce,addNum} = countStore.actions

//獲取reducer函式
const reducer = countStore.reducer

export {add,reduce,addNum}

export default reducer

(2)呼叫actionCreater的時候傳遞引數,引數會被傳遞到action物件的payload屬性上

<div>
        <button onClick={()=>{
          dispatch(reduce())
        }}>-</button>
        <span>{count}</span>
        <button onClick={()=>{
          dispatch(add())
        }}>+</button>
        <button onClick={()=>{
          dispatch(addNum(10))
        }}>
          +10
        </button>
        <button onClick={()=>{
          dispatch(addNum(20))
        }}>
          +20
        </button>
      </div>

//呼叫actionCreater的時候傳遞引數

4.非同步操作

(1)配置store

(2)同步修改

const channelStore=createSlice({
    name : 'channel', //定義子store的名字
    initialState :{
        channelList : [] //初始化資料的狀態
    },
    reducers:{
      //定義修改資料的同步方法 setList(state,action){ state.channelList
= action.payload } } })

(3)非同步修改

//非同步請求
 const {setList} = channelStore.actions
const channelAsync=()=>{
    return async (dispatch)=>{
       const res = await axios.get('。。。') //封裝非同步請求獲取資料
       dispatch(setList(res.data.data.channels)) //呼叫同步actionCreater傳入非同步資料生成的一個action物件,並使用dispatch提交
    }
}

(4)使用store的資料

(5)diapatch提交action物件更新store


 import {channelAsync} from './store/modules/channelStore'
const {channelList} = useSelector(state=>state.channel)
const dispatch = useDispatch()
  //React元件中修改store中的資料需要藉助另一個hook函式 useDispatch ,他的作用是生成提交action物件的dispatch函式
  useEffect(()=>{
    dispatch(channelAsync()//非同步操作生成的就不是一個action物件了 是一個action函式)
  },[dispatch])

相關文章