hook+reduxjs/toolkit +ts 使用

1. 依賴安裝 @reduxjs/toolkit react-redux typescript

npm install @reduxjs/toolkit react-redux typescript --save-dev

2. 創(chuàng)建公共倉庫 store.ts

  1. 使用configureStore 注冊 store
  2. 導(dǎo)出 state類型和dispatch的類型,方便后續(xù)代碼引用
  3. counterSlice為單個reducer,注意 reducer是唯一的
import { configureStore } from '@reduxjs/toolkit';

import counterSlice from './slice/counter';

const store = configureStore({
  reducer: {
    counter: counterSlice, // 注冊reducer
  },
});

// 導(dǎo)出state 類型
export type TRootState = ReturnType<typeof store.getState>;
// 導(dǎo)出dispatch類型
export type TAppDisPatch = typeof store.dispatch;

export default store;

3. 根組件配置store

index.tsx

import "./index.css";
import React from "react";
import ReactDOM from "react-dom/client";
import { Provider } from "react-redux";

import App from "./App";
import reportWebVitals from "./reportWebVitals";
import store from "./store/store";

const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
root.render(
    <React.StrictMode>
        <Provider store={store}>
            <App />
        </Provider>
    </React.StrictMode>
);

reportWebVitals();

4. createSlice ,創(chuàng)建單個reducer

  1. 創(chuàng)建slice

使用createSlice方法創(chuàng)建一個slice。每一個slice里面包含了reducer和actions携添,可以實現(xiàn)模塊化的封裝删窒。

  1. 關(guān)鍵屬性
  1. name
    命名空間螟蝙,可以自動的把每一個action進(jìn)行獨立源武,解決了action的type出現(xiàn)同名的文件。在使用的時候默認(rèn)會把使用name/actionName舱污。
  1. initialState
    state數(shù)據(jù)的初始值呀舔。
  1. reducers
    定義的action。由于內(nèi)置了immutable插件扩灯,可以直接使用賦值的方式進(jìn)行數(shù)據(jù)的改變媚赖,不需要每一次都返回一個新的state數(shù)據(jù)。
import { createSlice, PayloadAction } from "@reduxjs/toolkit";

import { setCountAsync } from "./asyncThunk/setCountAsync";

type TSliceInitData = { counter: number };

// 初始化state
const initialState: TSliceInitData = {
    counter: 0,
};

const counterSlice = createSlice({
    name: "counter", // 唯一名字
    initialState,
    reducers: {
        add: (state, action: PayloadAction<number>) => {
            state.counter += action.payload;
        },
        sub: (state, action: PayloadAction<number>) => {
            if (state.counter - action.payload < 0) {
                return;
            }
            state.counter -= action.payload;
        },
    },
    extraReducers: (builder) => {
        builder
            .addCase(setCountAsync.pending, (state) => {
                // 等待狀態(tài)
                console.log("pending", state);
            })
            .addCase(setCountAsync.rejected, (state) => {
                // 失敗狀態(tài)
                console.log("pending", state);
            })
            .addCase(setCountAsync.fulfilled, (state, action) => {
                // 成功狀態(tài)
                console.log("fulfilled", state);
                console.log("fulfilled", action);
                state.counter += action.payload;
            });
    },
});

// 注冊到store中
export default counterSlice.reducer;
// dispatch 使用
export const { add, sub } = counterSlice.actions;
  1. 導(dǎo)出

1.counterSlice.actions 導(dǎo)出所有的修改函數(shù)方便頁面使用
2.counterSlice.reducer 導(dǎo)出reducer在 store里面使用

  1. 具體reducer 函數(shù)的參數(shù)

1.參數(shù)1: 當(dāng)前slice的state數(shù)據(jù)
2.參數(shù)2: 對象{type:"",payload:傳參}
3.type:counter/getCount

5. 頁面使用

  1. 關(guān)鍵hook介紹

1.useSelector():返回指定的state const counter = useSelector(state=>state.rootCouter.counter);
2.useDispatch(): 修改函數(shù) const dispatch = useDispatch() dispatch(getCount())

  1. 優(yōu)化hook珠插,二次封裝后統(tǒng)一處理后暴露新的hook
    useReduxHook.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";

import { TAppDisPatch, TRootState } from "../store";

//此處對redux中的useDispatch, useSelector 進(jìn)行二次封裝方便項目中調(diào)用
export const useAppDispatch = () => useDispatch<TAppDisPatch>();
export const useAppSelector: TypedUseSelectorHook<TRootState> = useSelector;
  1. 頁面使用
import React from "react";

import { useAppDispatch, useAppSelector } from "../../store/hooks/useReduxHook";
import { setCountAsync } from "../../store/slice";
import { add, sub } from "../../store/slice/counter";
import styles from "./index.module.css";

type TCounter = { name?: string; title?: string };

enum EButtonType {
    ADD = "添加5",
    DEL = "刪除2",
}

const Counter: React.FC<TCounter> = () => {
    const dispatch = useAppDispatch();
    const { counter } = useAppSelector((state) => state.counter);

    const buttonList = [
        {
            show: true,
            element: (
                <button
                    onClick={() => {
                        dispatch(add(5));
                        setCount((state) => state + 1);
                    }}
                    key={"add"}
                >
                    {EButtonType.ADD}
                </button>
            ),
        },
        {
            show: true,
            element: (
                <button
                    onClick={() => {
                        dispatch(sub(2));
                        setCount((state) => state - 1);
                    }}
                    key={"del"}
                >
                    {EButtonType.DEL}
                </button>
            ),
        },
    ];

    return (
        <>
            <div>{buttonList.filter((item) => item.show).map((item) => item.element)}</div>
            <h2 className={styles.counter}>當(dāng)前:{counter}</h2>
        </>
    );
};

export { Counter };

  1. 頁面截圖


    image.png

6. createAsyncThunk 的使用惧磺,主要用于異步請求

1.接受一個動作類型字符串和一個返回Promise函數(shù),并生成一個pending/fulfilled/rejected基于該Promise分派動作類型的 thunk
2.參數(shù)1: slice的name/命名空間/函數(shù)名,參數(shù)2:執(zhí)行函數(shù)
asyncThunk setCountAsync.ts
使用promise模擬接口請求

import { createAsyncThunk } from "@reduxjs/toolkit";

const setCount = (payload: number = 0): Promise<number> => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(payload + 10);
        }, 1000);
    });
};

const prefix = "counter/getCount";
export const setCountAsync = createAsyncThunk(prefix, async (payload?: number) => {
    const res = await setCount(payload);

    // 此處返回的結(jié)果丧失,會在fulfilled中作為payload的值
    return res;
});

7. extraReducer

異步函數(shù)配置
對應(yīng)pending豺妓、rejected惜互、fulfilled三種狀態(tài)布讹,

extraReducers: (builder) => {
        builder
            .addCase(setCountAsync.pending, (state) => {
                // 等待狀態(tài)
                console.log("pending", state);
            })
            .addCase(setCountAsync.rejected, (state) => {
                // 失敗狀態(tài)
                console.log("pending", state);
            })
            .addCase(setCountAsync.fulfilled, (state, action) => {
                // 成功狀態(tài)
                console.log("fulfilled", state);
                console.log("fulfilled", action);
                state.counter += action.payload;
            });
    },

8. 各種中間件待補充

9. 最終目錄結(jié)構(gòu)

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市训堆,隨后出現(xiàn)的幾起案子描验,更是在濱河造成了極大的恐慌,老刑警劉巖坑鱼,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膘流,死亡現(xiàn)場離奇詭異絮缅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)呼股,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門耕魄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人彭谁,你說我怎么就攤上這事吸奴。” “怎么了缠局?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵则奥,是天一觀的道長。 經(jīng)常有香客問我狭园,道長读处,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任唱矛,我火速辦了婚禮罚舱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘揖赴。我一直安慰自己馆匿,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布燥滑。 她就那樣靜靜地躺著渐北,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铭拧。 梳的紋絲不亂的頭發(fā)上赃蛛,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機(jī)與錄音搀菩,去河邊找鬼呕臂。 笑死,一個胖子當(dāng)著我的面吹牛肪跋,可吹牛的內(nèi)容都是我干的歧蒋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼州既,長吁一口氣:“原來是場噩夢啊……” “哼谜洽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起吴叶,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤阐虚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蚌卤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體实束,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡奥秆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了咸灿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片构订。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖避矢,靈堂內(nèi)的尸體忽然破棺而出鲫咽,到底是詐尸還是另有隱情,我是刑警寧澤谷异,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布分尸,位于F島的核電站,受9級特大地震影響歹嘹,放射性物質(zhì)發(fā)生泄漏箩绍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一尺上、第九天 我趴在偏房一處隱蔽的房頂上張望材蛛。 院中可真熱鬧,春花似錦怎抛、人聲如沸卑吭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豆赏。三九已至,卻和暖如春富稻,著一層夾襖步出監(jiān)牢的瞬間掷邦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工椭赋, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留抚岗,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓哪怔,卻偏偏與公主長得像宣蔚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子认境,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容