状态管理(redux)
大约 3 分钟
状态管理(redux)
介绍
Redux 是 JavaScript 应用的状态容器,提供可预测的状态管理。 Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法。它围绕 Redux 核心,并包含我们认为对于构建 Redux 应用必不可少的软件包和功能。Redux Toolkit 建立在我们建议的最佳实践中,简化了大多数 Redux 任务,防止了常见错误,并使编写 Redux 应用程序更加容易。
安装
npm install @reduxjs/toolkit react-redux
先创建 store 目录
store/modules/counterStore.js
import { createSlice } from "@reduxjs/toolkit";
const counterStore = createSlice({
// 1. name:用作生成的 action type 的前缀
name: 'counter',
// 2. initialState:reducer的初始state
initialState: {
count: 0
},
// 3. reducers:对象,键是字符串,值是处理特定 actions 的 “case reducer” 函数
reducers: {
increment(state) {
state.count ++;
},
decrement(state) {
state.count --;
}
}
})
// 结构出创建 action 对象的函数 (actionCreater)
const {increment, decrement} = counterStore.actions;
// 创建 reducer 函数
const counterReducer = counterStore.reducer;
// 导出 创建 action对象的 函数和reducer函数
export {increment, decrement};
export default counterReducer;
store/index.js
// 通过 configureStore 创建根store组合子模块
import { configureStore } from "@reduxjs/toolkit";
// 导入 counter 的 reducer
import counterReducer from "./modules/counterStore";
const store = configureStore({
reducer: {
counter: counterReducer
}
})
export default store;
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
// 引入 store
import store from './store';
// react-redux 中的 Provider 注入 store
import { Provider } from 'react-redux';
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
App.jsx
import { useSelector, useDispatch } from "react-redux";
import {increment, decrement} from './store/modules/counterStore'
function App() {
// 1. 在组件中通过 useSelector 获取store中的数据
// state.counter 的 counter 对应 `store/index.js` 中 reducer下的 counter
const {count} = useSelector(state => state.counter);
// 2. 在组件中通过 useDispatch 生成提交 action 对象的dispatch函数
const dispatch = useDispatch()
return (
<>
<button onClick={() => dispatch(increment())}>+</button>
<span>{count}</span>
<button onClick={() => dispatch(decrement())}>-</button>
</>
)
}
export default App;
结果

进阶
提交action 时传参
store的reducers方法中除了 state,还有个 action 参数,通过 action.payload 可以获得传入的参数:
修改store/modules/counterStore.js
,在reducers
中新增addToNum
:
import { createSlice } from "@reduxjs/toolkit";
const counterStore = createSlice({
// 1. name:用作生成的 action type 的前缀
name: 'counter',
// 2. initialState:reducer的初始state
initialState: {
count: 0
},
// 3. reducers:对象,键是字符串,值是处理特定 actions 的 “case reducer” 函数
reducers: {
increment(state) {
state.count ++;
},
decrement(state) {
state.count --;
},
// 此处为新增
addToNum(state, action) {
state.count += action.payload; // payload 为固定属性,用来传参
}
}
})
// 解构并导出新增的 addToNum
// 结构出创建 action 对象的函数 (actionCreater)
const {increment, decrement,addToNum} = counterStore.actions;
// 创建 reducer 函数
const counterReducer = counterStore.reducer;
// 导出 创建 action对象的 函数和reducer函数
export {increment, decrement,addToNum};
export default counterReducer;
在App.jsx
新增 +10、+20
两个按钮
import { useSelector, useDispatch } from "react-redux";
import {increment, decrement, addToNum} from './store/modules/counterStore'
function App() {
// 1. 在组件中通过 useSelector 获取store中的数据
// state.counter 的 counter 对应 `store/index.js` 中 reducer下的 counter
const {count} = useSelector(state => state.counter);
// 2. 在组件中通过 useDispatch 生成提交 action 对象的dispatch函数
const dispatch = useDispatch()
return (
<>
<button onClick={() => dispatch(increment())}>+</button>
<span>{count}</span>
<button onClick={() => dispatch(decrement())}>-</button>
{/* 按传入的参数控制增加 */}
<button onClick={() => dispatch(addToNum(10))}>+10</button>
<button onClick={() => dispatch(addToNum(20))}>+20</button>
</>
)
}
export default App;
效果:

异步操作
新建store/modules/channelStore.js文件,
- 创建
store
的方法保持不变,配置好同步修改状态的方法 - 单独封装一个函数,在函数内部
return
一个新函数,该新函数中:- 封装异步请求获取数据
- 调用同步
actionCreater
传入异步数据,生成一个action
对象,并使用dispatch
提交 - 组件中
dispatch
的写法保持不变
import { createSlice } from '@reduxjs/toolkit';
import axios from 'axios'
const channelStore = createSlice({
name: 'channel',
initialState: {
channelList: []
},
reducers: {
setChannelList(state, action) {
state.channelList = action.payload
}
}
})
const {setChannelList} = channelStore.actions;
const channelReducer = channelStore.reducer
// 异步请求部分: 1. 新建一个函数
const fetchChannelList = () => {
// 2. return 一个函数
return async (dispatch) => {
// 3. 发送异步请求获取数据
const res = await axios.get('http://geek.itheima.net/v1_0/channels');
// 4. dispatch 提交同步 setChannelList 函数
dispatch(setChannelList(res.data.data.channels))
}
}
// 5.导出异步逻辑函数
export {fetchChannelList}
export default channelReducer;
store/index.js
import counterReducer from "./modules/counterStore";
import channelReducer from "./modules/channelStore";
const store = configureStore({
reducer: {
counter: counterReducer,
channel: channelReducer
}
})
App.jsx
组件中在 useEffect
中调用异步操作函数
import { fetchChannelList } from "./store/modules/channelStore";
...
const {channelList} = useSelector(state => state.channel);
useEffect(() => {
dispatch(fetchChannelList())
}, [dispatch])
...
function App() {
return (
...
<ul>
{
channelList.map(item => <li key={item.id}>{item.name}</li>)
}
</ul>
...
)