目录
使用js来编写代码,方便理解一些
1、搭建环境
首先,先要新建一个react项目,有了react项目之后就安装好依赖
npm install @reduxjs/toolkit
npm install react-redux
然后在src文件目录下新建一个名为store/stores文件夹(理论上其他也行,所有开发者都约定好即可),有关状态管理的数据都会存放在这里
这只是一个实例,store这个命名算是约定熟成,虽然可以起个别的名字,但是为了方便团队间合作约定写成store更容易让代码更好维护管理以及新开发者迅速找到对应位置。跟components文件夹放组件一样的道理。
2、Redux Toolkit 包含了什么
在中文版官方文档中可以直接看到以下的话语
看起来有点难懂,但是没关系我们先知道一些知识就好了,接下来是redux toolkit使用示例
3、使用示例
(1)创建user切片
在前面写好的store文件下新建一个user.js文件夹:
主要使用的是createSlice
import { createSlice } from "@reduxjs/toolkit"
const useSlice = createSlice({
name: "user",
initialState: { // 初始状态
name: "张三",
age: 18,
},
reducers: { // 定义方法
setName (state, action) {
state.name = action.payload
},
setAge(state, action) {
state.age = action.payload
}
}
})
export const { setName, setAge } = useSlice.actions // 导出方法
export default useSlice.reducer // 导出reducer
在react的状态当中,有一个规则是数据不可变,大白话讲就是这个state不应该直接修改,所以在代码中会直接生成一个新数据去覆盖它。遵循这个规则的话就是会写成setAge这个样子:
import { createSlice } from "@reduxjs/toolkit"
const useSlice = createSlice({
name: "user",
initialState: { // 初始状态
name: "张三",
age: 18,
},
reducers: { // 定义方法
setName (state, action) {
state.name = action.payload
},
setAge(state, action) {
return {
...state,
age: action.payload
}
}
}
})
export const { setName, setAge } = useSlice.actions // 导出方法
export default useSlice.reducer // 导出reducer
redux toolkit支持上面两种写法,所以写哪一种看个人爱好了
还可以继续写不同的文件在store里,对状态进行分类存放,对不同的分类都称为切片
在这里写一下,为什么在user.js要有以下两行代码:
export const { setName, setAge } = useSlice.actions // 导出方法
export default useSlice.reducer // 导出reducer
直观感受就是很多余,为什么需要这样编写
1.
export const { setName, setAge } = useSlice.actions
作用:导出该 slice 的 action creators(
setName
和setAge
),供组件或其他地方调用。为什么需要单独导出?
在组件中,你需要通过
dispatch(setName("Alice"))
这样的方式来触发状态更新。如果这里不导出这些 actions,外部代码就无法使用它们。虽然可以直接通过
useSlice.actions.setName
访问,但直接解构并导出会更清晰,方便调用。示例:
// 在其他组件中
import { setName } from './userSlice';
dispatch(setName("Bob")); // 直接使用导出的 action2.
export default useSlice.reducer
作用:导出 slice 的 reducer,供 Redux store 合并使用。
为什么需要默认导出?
Redux store 需要组合所有 slice 的 reducer(比如通过
combineReducers
)。通常会在 store 的配置文件中导入各个 slice 的 reducer:// store.js import userReducer from './userSlice'; // 这里导入的就是 useSlice.reducer const rootReducer = combineReducers({ user: userReducer, // 其他 reducer... });默认导出是为了简化导入语法(
import userReducer from './user'
),符合 Redux 的约定俗成
如果不这样写会怎样?
如果不导出 actions,外部代码需要直接访问
useSlice.actions.setName
,这会增加耦合性(调用方需要知道 slice 的内部结构)。如果不默认导出 reducer,store 配置时需要写更长的路径(比如
import { reducer as userReducer } from './user'
),不够简洁
总结
这两行代码是 Redux Toolkit 的标准模式:
导出 actions:方便组件调用
导出 reducer:方便 store 组合
虽然看起来冗余,但这是为了职责分离和代码可维护性。如果项目中有多个 slice,这种模式能保持一致性,减少认知负担
(2)合并切片得到store
将前面写好的切片合并,一般是在store文件夹下新建一个index.js文件来合并切片,这里主要使用的是configureStore,代码如下:
import { configureStore } from '@reduxjs/toolkit';
import User from './user';
export default configureStore({
reducer: {
user: User.reducer,
// 有多少切片就一个个写进来即可
}
})
(3)配置store和使用store
(1)配置
在index.jsx文件或者main.jsx文件进行配置
先添加以下代码,将上面的index.js文件导入进去:
import store from './store';
然后用Provider组件包裹住<APP />,并且给属性绑定store,示例如下:
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
// <React.StrictMode>
<Provider store={store}>
<App />
</Provider>
// </React.StrictMode>
);
(2)使用
在需要使用状态的组件中进行编写代码,用到useSelector来拿数据,useDispatch来调用方法
import React from "react";
import { useSelector, useDispatch } from "react-redux";
const PageOne = () => {
const user = useSelector((state) => state.user);
const dispatch = useDispatch();
return (
<div>
<h1>Page One</h1>
<div>{user.age}</div>
<button onClick={() => {
dispatch({ type: "user/setAge" , payload: user.age + 1});
}}>年龄+1</button>
</div>
)
}
export default PageOne;
但是这样的话这个 dispatch({ type: "user/setAge" , payload: user.age + 1})不够优雅,我们可以换一个优雅体面的方式
先将user引入组件中,这样就可以更方便的使用了,跟前面解释export const { setName, setAge } = useSlice.actions
的写法的原因给callback了
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import userSlice from "../../stores/user"; // 引入userSlice
const { setName, setAge } = userSlice.actions; // 解构出actions中的方法
const PageOne = () => {
const user = useSelector((state) => state.user);
const dispatch = useDispatch();
return (
<div>
<h1>Page One</h1>
<div>{user.age}</div>
<button onClick={() => {
dispatch(setName("李四"));
dispatch(setAge(user.age + 1));
}}>年龄+1, 改名李四</button>
</div>
)
}
export default PageOne;
好了,toolkit的用法基本就是这样,学会了就可以在编程中一边练一边不断学习更高阶的用法了,冲冲冲