使用redux-toolkit狀態管理

概述

redux-toolkit 是redux封裝的工具包,底層還是redux,提供了configureStore、createSlice等方法更簡潔的編寫方式,如需瞭解更多redux-toolkit

API

名稱 用途
configureStore 創建store實例
createSlice 創建切片,相當於模塊劃分,包含state,reducer等
useDispatch 用於分發任務,reducer處理state
useSelector 接受一個函數,用於取出state
createAction createAction 接受一個 action 類型字符串作爲參數,並返回一個使用該類型字符串的 action creator 函數。
createReducer 創建reducer ,接受state,和定義的action
createAsyncThunk 創建一個異步函數生成一個promise,可以利用這個promise狀態的改變,執行一些生命週期函數
createSelector 創建類似 react memo 的記憶選擇器,來達到性能優化
  1. configureStore configureStore 主要幫助我們創建標準 redux 的函數抽象,爲 store 添加默認配置以獲得更好的開發體驗。configureStore 方法提供 5 個參數:reducer 用來配置我們的 reducer 函數。如果他是一個函數,它將直接用作 store 的 root reducer。如果它是 slices 的對象,例如 {users : usersReducer, posts : postsReducer}, configureStore 將通過將此對象傳遞給 ReduxcombineReducers 函數,它將自動的創建 root reducer。 下面是一段 configureStore 的示例代碼:
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
import todoReducer from '../features/todo/todoSlice'
import reducer from '../reduxTodo/reducer'

export const store = configureStore({
  reducer: {
    counter: counterReducer,
    todoReducer: reducer,
    todo: todoReducer
  },
})

middleware middleware 它提供我們中間件的配置,如果未提供,configureStore 將調用 getDefaultMiddleware 並使用它返回的中間件函數數組。

如果我們希望添加或自定義默認中間件,我們可以傳遞一個回調函數,該函數將接收 getDefaultMiddleware 作爲其參數,並返回一箇中間件數組。

示例代碼如下:

import logger from 'redux-logger'

const store = configureStore({
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger),
})

getDefaultMiddleware doc 這裏可以查看默認配置都有什麼中間件。

devTools 如果它是一個布爾值,它將用於 configureStore 是否應自動啓用對 Redux DevTools 瀏覽器擴展的支持。

如果它是一個對象,則將啓用 DevTools 擴展,並將選項對象傳遞給 composeWithDevtools()。 有關可用的特定選項的列表,請參閱 EnhancerOptions 的 DevTools 擴展文檔。

preloadedState preloadedState 很好理解,就是傳遞給 Redux createStore 函數的初始狀態值。

enhancers 用於增加 Redux store 的能力。

如果定義爲數組,這些將傳遞給 Redux compose 函數,組合的增強器將傳遞給 createStore。

如果定義爲回調函數,它將使用沒有 DevTools 擴展的現有增強器數組(當前爲 applyMiddleware)調用,並應返回一個新的增強器數組。 這主要適用於需要在 applyMiddleware 前面添加 store 增強器的情況,例如 redux-first-router 或 redux-offline。

import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit'
import logger from 'redux-logger'
import { reduxBatch } from '@manaflair/redux-batch'
import counterReducer from '../features/counter/counterSlice'
import todoReducer, {Item} from '../features/todo/todoSlice'
import reducer from '../reduxTodo/reducer'

const preloadedState: Item[] = [
  {
    id: '5',
    text: 'redux',
    state: 'done'
  },
  {
    id: '7',
    text: 'toolkit',
    state: 'todo'
  }
]

export const store = configureStore({
  reducer: {
    counter: counterReducer,
    todoReducer: reducer,
    todo: todoReducer
  },
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger),
  devTools: process.env.NODE_ENV !== 'production',
  preloadedState: {
    todo: {
      list: preloadedState
    }
  },
  enhancers: [reduxBatch],
})
  1. createReducer 一個簡化創建 Redux slice 函數的實用程序。 它在內部使用 Immer 通過在 slice 中編寫“可變”代碼來大大簡化不可變的更新邏輯,並支持將特定的動作類型直接映射到 case reducer 函數,這些函數將在調度該動作時更新狀態。

示例代碼如下:

import { createAction, createReducer } from '@reduxjs/toolkit'

const increment = createAction('counter/increment')
const decrement = createAction('counter/decrement')
const incrementByAmount = createAction('counter/incrementByAmount')

const initialState = { value: 0 }

const counterReducer = createReducer(initialState, (builder) => {
  builder
    .addCase(increment, (state, action) => {
      state.value++
    })
    .addCase(decrement, (state, action) => {
      state.value--
    })
    .addCase(incrementByAmount, (state, action) => {
      state.value += action.payload
    })
})
這裏就不展開講解 createReducer ,大多數情況我們都會 slice 形式創建標準的 reducer 函數。詳細內容可以查看官方文檔 createReducer。
  1. createAction 用於定義 Redux action type 和創建者的輔助函數。

在 Redux 中定義 action 的常用方法是分別聲明一個 action 類型常量和一個用於構造該類型 action 的動作創建者函數。

import { createAction } from '@reduxjs/toolkit'

const increment = createAction('counter/increment')

let action = increment()
// { type: 'counter/increment' }

action = increment(3)
// returns { type: 'counter/increment', payload: 3 }

console.log(increment.toString())
// 'counter/increment'

console.log(`The action type is: ${increment}`)
// 'The action type is: counter/increment'
大多數情況我們都會 slice 形式創建標準的 action 函數。詳細內容可以查看官方文檔 createAction。

3、useDispath,useAppSelector

import { useDispatch,useSelector,TypedUseSelectorHook } from 'react-redux';
import type { RootState,AppDispatch } from './index';

export const  useAppSelector:TypedUseSelectorHook<RootState>=useSelector
export const  useAppDispatch=()=>useDispatch<AppDispatch>();

//在頁面使用,取出state的值
const schemaTree = useAppSelector((state: RootState) => state.schemaTree)
//dispath操作
import React from 'react'
import { useDispatch } from 'react-redux'

export const CounterComponent = ({ value }) => {
  const dispatch = useDispatch()

  return (
    <div>
      <span>{value}</span>
      <button onClick={() => dispatch({ type: 'increment-counter' })}>
        Increment counter
      </button>
    </div>
  )
}

  1. createSlice createSlice 是編寫 Redux 邏輯的標準方法。

一個接受初始狀態、reducer 函數對象和“切片名稱”的函數,並自動生成與 reducer 和狀態對應的動作創建者和動作類型。

示例代碼如下:

import {createSlice, PayloadAction} from '@reduxjs/toolkit'

export interface TodoState {
    list: Item[]
}

export interface Item {
    id: string,
    text: string,
    state: string
}

const todos: Item[] = [
    {
        id: '1',
        text: 'react',
        state: 'done'
    },
    {
        id: '2',
        text: 'vue',
        state: 'todo'
    },
    {
        id: '3',
        text: 'angular',
        state: 'todo'
    }
]

const initialState: TodoState = {
    list: todos
}

export const todoSlice = createSlice({
    name: 'todoSlice',
    initialState,
    reducers: {
        add: (state, action: PayloadAction<Item>) => {
            state.list.push(action.payload)
        },
        remove: (state, action: PayloadAction<string>) => {
            const index = state.list.findIndex(item => item.id === action.payload)
            state.list.splice(index, 1)
        },
        toggle: (state, action: PayloadAction<string>) => {
            const current = state.list.filter(item => item.id === action.payload)[0]
            current.state = current.state === 'todo' ? 'done' : 'todo'
        }
    }
})

export const {add, remove, toggle} = todoSlice.actions

export default todoSlice.reducer
大多數情況下我們都會使用 createSlice 來編寫 redux 邏輯。
  1. createAsyncThunk 幫助我們編寫異步邏輯,例如接口調用。

一個接受 Redux 操作類型字符串的函數和一個返回 promise 的回調函數。它根據您傳入的操作類型前綴生成 promise 生命週期操作類型,並返回一個 thunk 操作創建者,它將運行 promise 回調並根據返回的 promise 調度生命週期操作。

這抽象了處理異步請求生命週期的標準方法。

示例代碼如下:

import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { RootState, AppThunk } from '../../app/store';
import { fetchCount } from './counterAPI';

export interface CounterState {
  value: number;
  status: 'idle' | 'loading' | 'failed';
}

const initialState: CounterState = {
  value: 0,
  status: 'idle',
};

export const incrementAsync = createAsyncThunk(
  'counter/fetchCount',
  async (amount: number) => {
    const response = await fetchCount(amount);
    return response.data;
  }
);

export const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload;
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(incrementAsync.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(incrementAsync.fulfilled, (state, action) => {
        state.status = 'idle';
        state.value += action.payload;
      });
  },
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;

export const selectCount = (state: RootState) => state.counter.value;

export const incrementIfOdd = (amount: number): AppThunk => (
  dispatch,
  getState
) => {
  const currentValue = selectCount(getState());
  if (currentValue % 2 === 1) {
    dispatch(incrementByAmount(amount));
  }
};

export default counterSlice.reducer

更多使用方法和詳細的內容可以查看官方文檔 createAsyncThunk

  1. createSelector 可以幫助我們創建類似 react memo 的記憶選擇器,來達到性能優化。

它通過 Reselect 庫中的 createSelector 方法來實現。

示例代碼如下:

import React from 'react'
import { useSelector } from 'react-redux'
import { createSelector } from 'reselect'

const selectNumCompletedTodos = createSelector(
  (state) => state.todos,
  (todos) => todos.filter((todo) => todo.completed).length
)

export const CompletedTodosCounter = () => {
  const numCompletedTodos = useSelector(selectNumCompletedTodos)
  return <div>{numCompletedTodos}</div>
}

export const App = () => {
  return (
    <>
      <span>Number of completed todos:</span>
      <CompletedTodosCounter />
    </>
  )
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章