reduxjs/toolkit基本使用案列
更多介绍见官网
安装
npm install @reduxjs/toolkit react-redux @types/react-redux // redux及工具包
npm install @types/redux-logger redux-logger //日志包
npm install redux-persist //数据缓存
使用
1、创建slice
同步使用 counterSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
export interface CounterState {
value: number
title: string
}
const initialState: CounterState = {
value: 0,
title: 'redux toolkit pre',
}
// 创建一个 Slice
export const counterSlice = createSlice({
name: 'counter',
initialState,
// 定义 reducers 并生成关联的操作
reducers: {
// 定义一个加的方法
increment: state => {
state.value += 1
},
// 定义一个减的方法
decrement: state => {
state.value -= 1
},
incrementByAmount: (state, action: PayloadAction<{ vaule: number }>) => {
// action 里面有 type 和 payload 两个属性,所有的传参都在payload里面
// console.log(action)
// {"type": "counter/incrementByAmount","payload": {"vaule": 2}}
state.value += action.payload.vaule
},
},
})
// 导出加减的方法
export const { increment, decrement, incrementByAmount } = counterSlice.actions
// 默认导出
export default counterSlice.reducer
异步使用 movieSlice.ts
import {
createAsyncThunk,
createSlice,
Draft,
PayloadAction,
} from '@reduxjs/toolkit'
// 引入其他 slice 生成的 action
import { increment } from './counterSlice'
export interface MovieState {
list: any[]
totals: number
}
const initialState: MovieState = {
list: [],
totals: 0,
}
// 请求电影列表
const getMovieListApi = () =>
fetch(
'https://pcw-api.iqiyi.com/search/recommend/list?channel_id=1&data_type=1&mode=24&page_id=1&ret_num=48',
).then(res => res.json())
// thunk函数允许执行异步逻辑, 通常用于发出异步请求。
// createAsyncThunk 创建一个异步action,方法触发的时候会有三种状态:
// pending(进行中)、fulfilled(成功)、rejected(失败)
export const getMovieData = createAsyncThunk('movie/getMovie', async () => {
const res = await getMovieListApi()
return res
})
// 创建一个 Slice
export const movieSlice = createSlice({
name: 'movie',
initialState,
reducers: {
// 数据请求完触发
loadDataEnd: (
state: Draft<MovieState>,
action: PayloadAction<{ list: any[] }>,
) => {
state.list = action.payload.list
state.totals = action.payload.list.length
},
},
// extraReducers 字段让 slice 处理在别处定义的 actions,
// 包括由 createAsyncThunk 或其他slice生成的actions。
extraReducers(builder) {
// 处理其他 slice 生成的 actions
builder.addCase(increment, state => {
// increment方法触发时的处理
state.list.push({ name: '加' })
state.totals += 1
})
// 处理createAsyncThunk 生成的 actions
builder
.addCase(getMovieData.pending, state => {
console.log('🚀 ~ 进行中!')
})
.addCase(getMovieData.fulfilled, (state, { payload }) => {
console.log('🚀 ~ fulfilled', payload)
state.list = payload.data.list
state.totals = payload.data.list.length
})
.addCase(getMovieData.rejected, (state, err) => {
console.log('🚀 ~ rejected', err)
})
},
})
// 导出方法
export const { loadDataEnd } = movieSlice.actions
// 默认导出
export default movieSlice.reducer
2、配置store
store.ts
import { configureStore, combineReducers } from '@reduxjs/toolkit'
import logger from 'redux-logger'
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
// persistStore 为redux-persist内置的状态管理仓库;persistReducer 为内置的切片管理;
import { persistStore, persistReducer } from 'redux-persist'
// import storage from 'redux-persist/lib/storage' // 本地存储
import storage from 'redux-persist/lib/storage/session' // 会话存储
// 多个Slice的引入;
import counterSlice from './modules/counterSlice'
import movieSlice from './modules/movieSlice'
// 配置要存储的Slice;
const persistConfig = {
key: 'root', // key是放入localStorage中的key
storage,
// whitelist: ['language'], // 需要缓存的数据 默认缓存所有
// blacklist: ['navigation'], // navigation不会被存入缓存中,其他会,适用于少部分数据需要实时更新
}
// 合并多个Slice
const rootReducer = combineReducers({
counter: counterSlice,
movie: movieSlice,
})
const myPersistReducer = persistReducer(persistConfig, rootReducer)
// configureStore创建一个redux数据
const store = configureStore({
reducer: myPersistReducer,
// 配置中间键
middleware: getDefaultMiddleware =>
getDefaultMiddleware({ serializableCheck: false }).concat(logger),
devTools: true,
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
// 二次封装:对useDispatch,useSelector进行封装,解决每次使用都要导入RootState,AppDispatch
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const persistor = persistStore(store)
export default store
3、注入store到react入口文件
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import { ConfigProvider } from 'antd'
import zh_CN from 'antd/lib/locale/zh_CN'
import { Provider } from 'react-redux'
import store, { persistor } from '@/store'
// PersistGate的作用是向下分发persistStore对象;
import { PersistGate } from 'redux-persist/lib/integration/react'
import '@/config/i18n'
import App from '@/App'
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
root.render(
<React.StrictMode>
<BrowserRouter>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<ConfigProvider locale={zh_CN}>
<App />
</ConfigProvider>
</PersistGate>
</Provider>
</BrowserRouter>
</React.StrictMode>,
)
4、页面中使用
test.tsx
import React from 'react'
// 引入对应的方法
import {
increment,
decrement,
incrementByAmount,
} from '@/store/modules/counterSlice'
import { getMovieData } from '@/store/modules/movieSlice'
// 如何操作store
// 方式一、比较繁琐,每个文件都得这样引入
// 引入相关的hooks
import { useSelector, useDispatch } from 'react-redux'
// 引入store类型
import type { RootState, AppDispatch } from '@/store'
// 方式二、比较简单
import { useAppDispatch, useAppSelector } from '@/store'
const ReduxToolkitTest: React.FC = () => {
// 使用:方式一
// // 通过useSelector直接拿到store中定义的counter
// const { value } = useSelector((store: RootState) => store.counter)
// // 通过useSelector直接拿到store中定义的movie
// const { list } = useSelector((store: RootState) => store.movie)
// // 通过useDispatch 派发事件
// const dispatch = useDispatch<AppDispatch>()
// 使用:方式二
// 通过useSelector直接拿到store中定义的counter
const { value } = useAppSelector(store => store.counter)
// 通过useSelector直接拿到store中定义的movie
const { list } = useAppSelector(store => store.movie)
// 通过useDispatch 派发事件
const dispatch = useAppDispatch()
return (
<div className="App">
<header className="App-header">
<p>{value}</p>
<button
onClick={() => {
dispatch(increment())
}}
>
加
</button>
<button
onClick={() => {
dispatch(decrement())
}}
>
减
</button>
<button
onClick={() => {
dispatch(incrementByAmount({ vaule: 2 }))
}}
>
加2
</button>
</header>
<hr />
<main>
<h1>电影列表</h1>
<button
onClick={() => {
dispatch(getMovieData())
}}
>
获取数据
</button>
<ul>
{list.map((item, index) => {
return <li key={index}> {item.name}</li>
})}
</ul>
</main>
</div>
)
}
export default ReduxToolkitTest