Redux Toolkit 快速使用(學(xué)習(xí)筆記)

安裝 Redux Toolkit 和 React-Redux

添加 Redux Toolkit 和 React-Redux 依賴包到你的項目中:

npm install @reduxjs/toolkit react-redux

創(chuàng)建 Redux Store

創(chuàng)建 src/store/index.js 文件。從 Redux Toolkit 引入 configureStore API。我們從創(chuàng)建一個空的 Redux store 開始,并且導(dǎo)出它:

// src/store/index.js
import { configureStore } from '@reduxjs/toolkit'

export default configureStore({
  reducer: {}
})

為 React 注入 Redux Store

創(chuàng)建 store 后,便可以在 React 組件中使用它。 在 src/index.js 中引入我們剛剛創(chuàng)建的 store , 通過 React-Redux 的 <Provider><App> 包裹起來,并將 store 作為 prop 傳入。

// src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import store from './store/index.js'
import { Provider } from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

創(chuàng)建 Redux State Slice

創(chuàng)建 src/store/modules/counterStore.js 文件。在該文件中從 Redux Toolkit 引入 createSlice API。

創(chuàng)建 slice 需要一個字符串名稱來標(biāo)識切片、一個初始 state 以及一個或多個定義了該如何更新 state 的 reducer 函數(shù)。slice 創(chuàng)建后 ,我們可以導(dǎo)出 slice 中生成的 Redux action creatorsreducer 函數(shù)。

// src/store/modules/counterStore.js
import { createSlice } from '@reduxjs/toolkit'

export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0
  },
  reducers: {
    increment: state => {
      // Redux Toolkit 允許我們在 reducers 寫 "可變" 邏輯。它
      // 并不是真正的改變狀態(tài)值,因為它使用了 Immer 庫
      // 可以檢測到“草稿狀態(tài)“ 的變化并且基于這些變化生產(chǎn)全新的
      // 不可變的狀態(tài)
      state.value += 1
    },
    decrement: state => {
      state.value -= 1
    },
    // 第二個參數(shù)action的payload屬性接收來自組件中dispatch action的傳參
    incrementByAmount: (state, action) => {
      state.value += action.payload
    }
  }
})
// 每個 case reducer 函數(shù)會生成對應(yīng)的 Action creators
export const { increment, decrement, incrementByAmount } = counterSlice.actions

export default counterSlice.reducer

將 Slice Reducers 添加到 Store 中

下一步,我們需要從計數(shù)切片中引入 reducer 函數(shù),并將它添加到我們的 store 中。通過在 reducer 參數(shù)中定義一個字段,我們告訴 store 使用這個 slice reducer 函數(shù)來處理對該狀態(tài)的所有更新。

// src/store/index.js
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'

export default configureStore({
  reducer: {
    counter: counterReducer
  }
})

在 React 組件中使用 Redux 狀態(tài)和操作

現(xiàn)在我們可以使用 React-Redux 鉤子讓 React 組件與 Redux store 交互。我們可以使用 useSelector 從 store 中讀取數(shù)據(jù),使用 useDispatch dispatch actions。

import { useSelector, useDispatch } from 'react-redux';
import {
  decrement,
  increment,
  incrementByAmount,
} from './store/modules/counterStore.js';

export default function ReduxCounter() {
  const count = useSelector((state) => state.counter.value);
  const dispatch = useDispatch();
  return (
    <div>
      <button onClick={() => dispatch(decrement())}>-</button>
      {count}
      <button onClick={() => dispatch(increment())}>+</button>
      {/* dispatch action傳遞的參數(shù)會在reducer函數(shù)的第二個參數(shù)action.payload進(jìn)行接收 */}
      <button onClick={() => dispatch(incrementByAmount(10))}>add 10</button>
    </div>
  );
}

用 Thunk 編寫異步邏輯

到目前為止,我們應(yīng)用程序中的所有邏輯都是同步的。首先 dispatch action,store 調(diào)用 reducer 來計算新狀態(tài),然后 dispatch 函數(shù)完成并結(jié)束。但是,JavaScript 語言有很多編寫異步代碼的方法,我們的應(yīng)用程序通常具有異步邏輯,比如從 API 請求數(shù)據(jù)之類的事情。我們需要一個地方在我們的 Redux 應(yīng)用程序中放置異步邏輯。

thunk 是一種特定類型的 Redux 函數(shù),可以包含異步邏輯。Thunk 是使用兩個函數(shù)編寫的:

  • 一個內(nèi)部 thunk 函數(shù),它以 dispatch 和 getState 作為參數(shù)
  • 外部創(chuàng)建者函數(shù),它創(chuàng)建并返回 thunk 函數(shù)

比如我們從 counterStore 導(dǎo)出一個函數(shù)incrementAsync,incrementAsync就是一個 thunk action creator。

// 下面這個函數(shù)就是一個 thunk ,它使我們可以執(zhí)行異步邏輯
// 你可以 dispatched 異步 action `dispatch(incrementAsync(10))` 就像一個常規(guī)的 action
// 調(diào)用 thunk 時接受 `dispatch` 函數(shù)作為第一個參數(shù)
// 當(dāng)異步代碼執(zhí)行完畢時,可以 dispatched actions
export const incrementAsync = amount => dispatch => {
  setTimeout(() => {
    dispatch(incrementByAmount(amount))
  }, 1000)
}

我們可以像使用普通 Redux action creator 一樣使用它們:

store.dispatch(incrementAsync(5))

但是,使用 thunk 需要在創(chuàng)建時將 redux-thunk middleware(一種 Redux 插件)添加到 Redux store 中。幸運的是,Redux Toolkit 的 configureStore 函數(shù)已經(jīng)自動為我們配置好了,所以我們可以繼續(xù)在這里使用 thunk。

當(dāng)你需要進(jìn)行 AJAX 調(diào)用以從服務(wù)器獲取數(shù)據(jù)時,你可以將該調(diào)用放入 thunk 中。這是一個寫得有點長的例子,所以你可以看到它是如何定義的:

// 外部的 thunk creator 函數(shù)
const fetchUserById = userId => {
  // 內(nèi)部的 thunk 函數(shù)
  return async (dispatch, getState) => {
    try {
      // thunk 內(nèi)發(fā)起異步數(shù)據(jù)請求
      const user = await userAPI.fetchById(userId)
      // 但數(shù)據(jù)響應(yīng)完成后 dispatch 一個 action
      dispatch(userLoaded(user))
    } catch (err) {
      // 如果過程出錯,在這里處理
    }
  }
}

dispatch thunk action creator

 useEffect(() => {
    dispatch(fetchUserById(5));
 }, [dispatch]);

總結(jié)

我們可以使用 Redux Toolkit configureStore API 創(chuàng)建一個 Redux store
  • configureStore 接收 reducer 函數(shù)來作為命名參數(shù)
  • configureStore 自動使用默認(rèn)值來配置 store
在 slice 文件中編寫 Redux 邏輯
  • 一個 slice 包含一個特定功能或部分的 state 相關(guān)的 reducer 邏輯和 action
  • Redux Toolkit 的 createSlice API 為你提供的每個 reducer 函數(shù)生成 action creator 和 action 類型
Redux reducer 必須遵循以下原則
  • 必須依賴 state 和 action 參數(shù)去計算出一個新 state
  • 必須通過拷貝舊 state 的方式去做 不可變更新 (immutable updates)
  • 不能包含任何異步邏輯或其他副作用
  • Redux Toolkit 的 createSlice API 內(nèi)部使用了 Immer 庫才達(dá)到表面上直接修改("mutating")state 也實現(xiàn)不可變更新(immutable updates)的效果
一般使用 “thunks” 來開發(fā)特定的異步邏輯
  • Thunks 接收 dispatch 和 getState 作為參數(shù)
  • Redux Toolkit 內(nèi)置并默認(rèn)啟用了 redux-thunk 中間件
使用 React-Redux 來做 React 組件和 Redux store 的通信
  • 在應(yīng)用程序根組件包裹 <Provider store={store}> 使得所有組件都能訪問到 store
  • 全局狀態(tài)應(yīng)該維護(hù)在 Redux store 內(nèi),局部狀態(tài)應(yīng)該維護(hù)在局部 React 組件內(nèi)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容