基础使用: redux Toolkit的使用
redux Toolkit之TypeScript使用
官文档中文地址:Redux Toolkit TypeScript 快速开始
store.ts
import {
configureStore,
combineReducers,
ThunkAction,
Action
} from '@reduxjs/toolkit'
import {
persistStore,
persistReducer
} from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import testSlice from './slice/testSlice'
import themeSlice from './slice/themeSlice'
import userSlice from './slice/userSlice'
import utilsSlice from './slice/utilsSlice'
export const rootReducer = combineReducers({
user: userSlice,
theme: themeSlice,
utils: utilsSlice,
test: testSlice
})
// 持久化
const persistConfig = {
key: 'wgh',
storage,
blacklist: ['utils', 'test'], // 黑名单:不持久化的slice
}
const myPersistReducer = persistReducer(persistConfig, rootReducer)
export const store = configureStore({
// reducer: {
// user: userSlice,
// theme: themeSlice
// }
reducer: myPersistReducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
serializableCheck: false
})
})
export const persistor = persistStore(store)
// 类型
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>;
自定义hooks
组件使用时将原来的 useDispatch
, useSelector
换成useAppDispatch
和 useAppSelector
即可
import { useDispatch, useSelector } from 'react-redux'
import type { TypedUseSelectorHook } from 'react-redux'
import type { RootState, AppDispatch } from './store'
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
// import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
// import type { RootState, AppDispatch } from './store';
// // Use throughout your app instead of plain `useDispatch` and `useSelector`
// export const useAppDispatch = () => useDispatch<AppDispatch>();
// export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
testSlice.ts
import { RootState, AppThunk } from '../store';
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
export interface TestState {
value: number
num: number
status: 'idle' | 'loading' | 'failed'
}
const initialState: TestState = {
value: 0,
num: 10,
status: 'idle',
}
// 模拟后端请求(异步)
export function fetchCount(amount = 1) {
return new Promise<{ data: number }>((resolve) =>
setTimeout(() => resolve({ data: amount }), 500)
);
}
// 异步:第一个参数相当于 type: "test/fetchCount"
export const incrementAsync = createAsyncThunk(
"test/fetchCount",
async (amount: number) => {
const res = await fetchCount(amount)
// 返回的值成为 "fulfilled "动作的有效载荷
return res.data
}
);
export const testSlice = createSlice({
name: 'test',
initialState,
reducers: {
increment: (state) => {
state.value ++
},
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload;
},
},
// 额外的reducers,包括但不限于createAsyncThunk产生的动作
extraReducers(builder) {
builder
.addCase(incrementAsync.pending, (state) => {
// incrementAsync执行准备阶段
state.status = 'loading'
})
.addCase(incrementAsync.fulfilled, (state, action) => {
// incrementAsync执行成功阶段
state.status = 'idle'
// 成功后执行的操作
// action.payload 是incrementAsync返回数据
state.value += action.payload
state.num+= action.payload
})
.addCase(incrementAsync.rejected, (state, action) => {
// incrementAsync执行失败阶段
state.status = 'failed'
console.log('error', action.error.message)
// state.error = action.error.message
})
}
})
// Action creators are generated for each case reducer function
export const { increment, incrementByAmount } = testSlice.actions
export default testSlice.reducer
// 函数选择器,内联定义
export const selectCount = (state: RootState) => state.test.value;
// 手工编写thunks:可以包含同步、异步逻辑或根据当前状态执行
export const incrementIfOdd =
(amount: number): AppThunk =>
(dispatch, getState) => {
// amount:组件传递的参数 currentValue:当前 num 值
const currentValue = selectCount(getState());
// 执行条件
if (currentValue % 2 === 1) {
dispatch(incrementByAmount(amount));
}
};
组件中使用
import { Button, Space } from 'antd'
import { useAppDispatch, useAppSelector } from '@/redux/hooks'
import { incrementIfOdd, increment, selectCount, incrementAsync, TestState } from '@/redux/slice/testSlice'
const Test= () => {
const test: TestState = useAppSelector(state => state.test)
const count = useAppSelector(selectCount)
const dispatch = useAppDispatch()
return (
<div style={{
display: 'flex',
flexDirection: 'column'
}}>
<Space>
<div>value: {count}</div>
<div>num: {test.num}</div>
<Button onClick={() => dispatch(increment())}>同步</Button>
<Button type="primary" onClick={() => dispatch(incrementAsync(5))}>异步</Button>
<Button danger onClick={() => dispatch(incrementIfOdd(count))}>条件</Button>
</Space>
</div>
)
}
export default Test