什么是Redux?
Redux是React最常用的集中状态管理工具,类似于Vue中的Pinia(Vuex),可以独立于框架运行。其作用是通过集中管理的方式管理应用的状态
特点:redux可以独立于组件之外对状态进行集中管理,各组件都可以使用store中的状态数据,同时,每个组件也可以通过固定的方式修改store中的数据,store中的数据一旦发生改变,那么所有使用此数据的组件都会发生改变
核心概念
- state:一个对象,存放着我们管理的数据状态
- action:一个对象,用来描述你想怎么改变数据
- reducer:一个函数,根据action的描述生成一个新的state
集成React配套工具
在React中使用redux,官方要求安装两个插件 Redux Toolkit 和 react-redux
1、Redux Toolkit(RTK)-官方推荐编写Redux逻辑的方式,是一套工具的集合,简化书写方式
- 简化store的配置方式
- 内置immer支持可变式状态修改
- 内置thunk更好的异步创建
2、react-redux 用来连接redux和React组件的中间件
目录结构
- 通常集中状态管理的部分都会单独创建一个store目录
- 应用通常会有很多个子store模块,所以创建一个modules目录,在内部编写业务分类的子store
- store中的入口文件index.js的作用是组合modules中所有的子模块,并导出store
//counterStore.js
import { createSlice } from "@reduxjs/toolkit";
const counterStore = createSlice({
name: "counter",
//初始化state
initialState: {
count: 0,
},
//修改数据方法 同步 支持直接修改
reducers: {
increment(state) {
state.count++;
},
decrement(state) {
state.count--;
},
},
});
//解构出来actionCreater函数
const { increment, decrement } = counterStore.actions;
//获取reducer
const reducer = counterStore.reducer;
//以按需导出方式 导出 actionCreater
export { increment, decrement };
//以默认导出方式 导出 reducer
export default reducer;
//index.js
import { configureStore } from "@reduxjs/toolkit";
//导入子模块
import counterReducer from "./modules/counterStore";
const store = configureStore({
reducer: {
counter: counterReducer,
},
});
export default store;
为react注入store
react-redux负责把Redux和React连接起来,内置Provider组件通过store参数把创建好的store实例注入到应用中,链接正式建立
//main.js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
// import App from "./App.tsx";
import Index from "./pages/index.tsx";
// import "./index.css";
import store from "./store";
import { Provider } from "react-redux";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<Provider store={store}>
<Index />
</Provider>
</StrictMode>
);
React组件使用store中的数据
在React组件中使用store中的数据,需要用到一个钩子函数 useSelector,它的作用是把store中的数据映射到组件中,使用样例如下
import { useSelector } from "react-redux";
function index() {
const { count } = useSelector((state) => state.counter);
return <div>主页面{count}</div>;
}
export default index;
0渲染出来了说明好使了
React组件修改store中的数据
React组件中修改store中的数据需要借助另外一个hook函数 useDispatch,它的作用是生成提交action对象的dispatch函数,使用样例如下:
import { useSelector, useDispatch } from "react-redux";
//导入创建action对象的方法
import { increment, decrement } from "../store/modules/counterStore";
function index() {
const { count } = useSelector((state) => state.counter);
//得到dispatch函数
const dispatch = useDispatch();
return (
<div>
主页面{count}
{/* 调用dispatch提交action对象 */}
<button onClick={() => dispatch(decrement())}>减少</button>
<button onClick={() => dispatch(increment())}>增加</button>
</div>
);
}
export default index;
提交action传参
在reducers的同步修改方法中添加action对象参数,在调用actionCreater的时候传递参数,参数会被传递到action对象payload属性上
//counterStore.js
import { createSlice } from "@reduxjs/toolkit";
const counterStore = createSlice({
name: "counter",
//初始化state
initialState: {
count: 0,
},
//修改数据方法 同步 支持直接修改
reducers: {
increment(state) {
state.count++;
},
decrement(state) {
state.count--;
},
addToNum(state, action) {
state.count = action.payload;
},
},
});
//解构出来actionCreater函数
const { increment, decrement, addToNum } = counterStore.actions;
//获取reducer
const reducer = counterStore.reducer;
//以按需导出方式 导出 actionCreater
export { increment, decrement, addToNum };
//以默认导出方式 导出 reducer
export default reducer;
import { useSelector, useDispatch } from "react-redux";
//导入创建action对象的方法
import { increment, decrement, addToNum } from "../store/modules/counterStore";
function index() {
const { count } = useSelector((state) => state.counter);
//得到dispatch函数
const dispatch = useDispatch();
return (
<div>
主页面{count}
{/* 调用dispatch提交action对象 */}
<button onClick={() => dispatch(decrement())}>减少</button>
<button onClick={() => dispatch(increment())}>增加</button>
<button onClick={() => dispatch(addToNum(10))}>+10</button>
<button onClick={() => dispatch(addToNum(20))}>+20</button>
</div>
);
}
export default index;
异步状态操作
- 创建store的写法保持不变,配置好同步修改状态的方法
- 单独封装一个函数,在函数内部return一个新函数,在新函数中
- 封装异步请求获取数据
- 调用同步actionCreater传入异步数据生成一个action对象,并使用dispatch提交
- 组件中dispatch的写法保持不变
//channelStore.js
import { createSlice } from "@reduxjs/toolkit";
const channelStore = createSlice({
name: "channel",
initialState: {
channelList: [],
},
reducers: {
setChannels(state, action) {
state.channelList = action.payload;
},
},
});
//异步请求部分
const { setChannels } = channelStore.actions;
const fetchChannelList = () => {
return async (dispatch) => {
const response = await getList();
console.log("response", response);
dispatch(setChannels(response));
};
};
function getList() {
const dataList = [];
setTimeout(() => {
dataList.push({
id: 1,
name: "111",
});
dataList.push({
id: 2,
name: "222",
});
dataList.push({
id: 3,
name: "333",
});
});
return dataList;
}
const reducer = channelStore.reducer;
export { fetchChannelList };
export default reducer;
//index.js
import { configureStore } from "@reduxjs/toolkit";
//导入子模块
import counterReducer from "./modules/counterStore";
import channelReducer from "./modules/channelStore";
const store = configureStore({
reducer: {
counter: counterReducer,
channel: channelReducer,
},
});
export default store;
//业务组件使用
import { useSelector, useDispatch } from "react-redux";
import { useEffect } from "react";
//导入创建action对象的方法
import { increment, decrement, addToNum } from "../store/modules/counterStore";
import { fetchChannelList } from "../store/modules/channelStore";
function index() {
const { count } = useSelector((state) => state.counter);
const { channelList } = useSelector((state) => state.channel);
//得到dispatch函数
const dispatch = useDispatch();
//使用useEffect触发异步请求执行
useEffect(() => {
dispatch(fetchChannelList());
}, [dispatch]);
return (
<div>
主页面{count}
{/* 调用dispatch提交action对象 */}
<button onClick={() => dispatch(decrement())}>减少</button>
<button onClick={() => dispatch(increment())}>增加</button>
<button onClick={() => dispatch(addToNum(10))}>+10</button>
<button onClick={() => dispatch(addToNum(20))}>+20</button>
<ul>
{channelList.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
}
export default index;
渲染成功