安装
yarn add @reduxjs/toolkit react-redux
安装 redux 开发工具 redux-devtools
yarn add redux-devtools -D
基本使用
在 src 中创建一个 store 文件,在 store 中创建 features 文件用来存放模块的数据
- 创建
counterSlice
import { createSlice } from "@reduxjs/toolkit"
export const counterSlice = createSlice({
name: 'counter',
initialState: {
count: 1,
title: 'redux toolkit pre'
},
reducers: {
increment(state, action) {
// 内置了immutable
state.count = state.count + 1
},
decrement(state) {
state.count -= 1
}
}
})
// 下面的actions与reducers中的对应
export const { increment, decrement } = counterSlice.actions
// 下面的reducer是暴露出去的initialState
export default counterSlice.reduce
- 在
store的index.js中进行合并
import { configureStore } from "@reduxjs/toolkit";
import counterSlice from "./features/counterSlice";
import recommendSlice from "./features/recommendSlice";
const store = configureStore({
reducer: {
counter: counterSlice,
recommend: recommendSlice
}
})
export default store
- 在全局的
index.js中将store全局共享
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import '@/assets/css/reset.css';
// redux-toolkit
import { Provider } from 'react-redux';
import store from './store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);
-
在组件中使用
下面的
state.counter对应到store中index的store.counter,最终拿到counterSlice的initialState
import React, { memo } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { increment, decrement } from '@/store/features/counterSlice'
const Counter = memo(() => {
const { count } = useSelector(state => state.counter)
const dispatch = useDispatch()
return (
<div>
<h2>{count}</h2>
<button onClick={e => dispatch(increment())}>+1</button>
<button onClick={e => dispatch(decrement())}>-1</button>
</div>
)
})
export default Counter
传递参数
参数可以在 dispatch 中进行传递,如下
import React, { memo, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { increment, decrement } from '@/store/features/counterSlice'
const SxRecommend = memo(() => {
const { count } = useSelector(state => state.counter)
return (
<div>
<h2>{count}</h2>
<button onClick={e => dispatch(increment({ step: 5 }))}>+1</button>
<button onClick={e => dispatch(decrement())}>-1</button>
</div>
)
})
export default SxRecommend
在 reducers 中定义的函数中的 action 参数中拿到传递过来的参数
import { createSlice } from "@reduxjs/toolkit"
export const counterSlice = createSlice({
。。。
reducers: {
increment(state, action) {
console.log(action);
// 内置了immutable
state.count = state.count + action.payload.step
}
}
})
。。。
也可以进行解构
increment(state, { payload }) {
state.count = state.count + payload.step
}
extraReducers
extraReducers 可以让在某个模块中触发其他模块的函数,并执行该函数时对本模块的数据进行操作,也可以用来操作异步请求(请看下面的异步请求)
如下:在 recommendSlice 模块执行 counterSlice 中的 increment 函数,并将本身的 topBanners 数据赋值为 increment 的参数
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import request from '@/services/request'
import { increment } from "./counterSlice";
export const getTopBanners = createAsyncThunk(
'getTopBanners',
async () => {
return await request({ url: '/banner' })
}
)
export const recommendSlice = createSlice({
name: 'recommend',
initialState: {
topBanners: []
},
reducers: {},
extraReducers: {
[increment]: (state, action) => {
state.topBanners = action.payload.step
},
[getTopBanners.fulfilled]: (state, { payload }) => {
return state = { ...state, topBanners: payload.banners }
}
}
})
export default recommendSlice.reducer
异步请求
createAsyncThunk
createAsyncThunk 可以帮助我们创建一个异步函数,并且会给函数定义与 Promise 一样的三种状态: pending 、 fulfilled、rejected
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import request from '@/services/request'
import { increment } from "./counterSlice";
export const getTopBanners = createAsyncThunk(
'getTopBanners',
async () => {
return await request({ url: '/banner' })
}
)
export const recommendSlice = createSlice({
name: 'recommend',
initialState: {
topBanners: []
},
reducers: {},
extraReducers: {
[getTopBanners.pending](state, action) {
console.log('进行中', state);
},
[getTopBanners.fulfilled]: (state, action) => {
console.log('请求成功', state);
return state = { ...state, topBanners: action.payload.banners }
},
[getTopBanners.rejected]: (state, action) => {
console.log('请求失败', state);
}
}
})
export default recommendSlice.reducer
基本流程
-
在
features中创建recommendSlice文件- 当
getTopBanners请求完成后的数据会作为参数action传递给extraReducers中对应的函数,也可以进行解构 - 如果不使用
async,会把then中的return res传递给extraReducers中对应的函数
- 当
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import request from '@/services/request'
export const getTopBanners = createAsyncThunk(
'getTopBanners',
async () => {
return await request({ url: '/banner' })
}
)
export const recommendSlice = createSlice({
name: 'recommend',
initialState: {
topBanners: []
},
reducers: {},
extraReducers: {
[getTopBanners.fulfilled]: (state, action) => {
console.log(action);
return state = { ...state, topBanners: action.payload.banners }
}
}
})
export default recommendSlice.reducer
- 在
index中进行合并
import { configureStore } from "@reduxjs/toolkit";
import counterSlice from "./features/counterSlice";
import recommendSlice from "./features/recommendSlice";
const store = configureStore({
reducer: {
counter: counterSlice,
recommend: recommendSlice
}
})
export default store
- 将
store全局共享 - 在组件中使用
import React, { memo, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { getTopBanners } from '@/store/features/recommendSlice'
const SxRecommend = memo(() => {
const { topBanners } = useSelector(state => state.recommend)
const dispatch = useDispatch()
useEffect(() => {
dispatch(getTopBanners())
}, [dispatch])
return (
<div>
<h2>SxRecommend</h2>
<div>
{
topBanners.map((item, index) => {
return <img key={item.imageUrl} src={item.imageUrl} />
})
}
</div>
</div>
)
})
export default SxRecommend
也可以把异步请求函数抽出来放到 services 模块进行管理,使用时直接导入即可
import request from './request'
import { createAsyncThunk } from "@reduxjs/toolkit";
export const getTopBanners = createAsyncThunk(
'getTopBanners',
async () => {
return await request({ url: '/banner' })
}
)