1. Redux基础用法
Redux 是一个用于 JavaScript 应用的状态管理库,它不依赖于任何 UI库,但常用于与 React 框架配合使用。它提供了一种集中式的状态管理方式,将应用的所有状态保存在一个单一的全局 Store(存储)中,使得状态的变化和共享变得更加可控和可预测。
✨Redux 的核心概念:
-
Store
Redux 的 Store 是一个对象,存储了应用的全部状态。应用中只有一个 Store,作为单一数据源。任何组件需要访问状态时都会从这个 Store 中获取数据。 -
Action
Action 是一个简单的 JavaScript 对象,用**来描述要执行的状态变化。**它通常包含两个部分:type
(字符串,描述 Action 的类型)和payload
(可选,用来传递需要修改的数据信息)。Action 是 Redux 中唯一触发状态更新的方式。 -
Reducer
Reducer 是一个纯函数,定义了应用在接收到不同 Action 时如何更新状态。它接收当前的状态和 Action,返回一个新的状态对象。 -
Dispatch
Dispatch 是 Redux 中触发 Action 的方法。调用store.dispatch(action)
可以将 Action 发送到 Store,从而触发 Reducer 更新状态。 -
Selectors
Selectors 是从 Store 中获取特定状态的函数,主要用于简化和集中获取逻辑,避免直接访问 Store 造成的代码冗余。 -
Middleware
Redux 中间件是在 dispatch 和 reducer 之间的一个逻辑层,可以用于处理异步操作(如 redux-thunk)或记录状态变化(如 redux-logger)。中间件增强了 Redux,使其能够处理复杂的逻辑和副作用。
简单计数器案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script src="https://cdn.bootcdn.net/ajax/libs/redux/4.2.0/redux.min.js"></script>
<body>
<button id="increment">+</button>
<span id="count">0</span>
<button id="decrement">-</button>
</body>
<script>
// 1.定义reducer函数
// 作用:根据不同的action对象,返回不同的新的state
// state:管理的数据初始状态
// action:对象 type 标记当前想要做什么样的修改
function reducer(state = { count: 0 }, action) {
// 数据不可变:基于原始状态生成一个新的状态
if (action.type === 'INCREMENT') {
return { count: state.count + 1 }
}
if (action.type === 'DECREMENT') {
return { count: state.count - 1 }
}
return state
}
// 2. 使用reducer函数创建store对象
const store = Redux.createStore(reducer)
// 3. 通过store对象的dispatch,修改store中的数据
const inBtn = document.getElementById('increment')
const deBtn = document.getElementById('decrement')
inBtn.addEventListener('click', () => {
store.dispatch({ type: 'INCREMENT' })
})
deBtn.addEventListener('click', () => {
store.dispatch({ type: 'DECREMENT' })
})
// 4. 监听store中数据的变化
//每次state发生变化的时候自动执行
store.subscribe(() => {
console.log('store数据变化了', store.getState())
document.getElementById('count').innerText = store.getState().count
})
</script>
</html>
2. React中使用Redux
在React中使用redux,官方要求安装俩个其他插件-ReduxToolkit
和react-redux
- Redux Toolkit(RTK): 官方推荐编写Redux逻辑的方式,是一套工具的集合,简化书写方式
- react-redux:用来 链接 Redux和 React组件的中间件
npm install @reduxjs/toolkit react-redux
目录结构:新建store文件夹,将子模块放在modules目录下,index.js为store入口文件。
创建 slice 需要一个字符串名称来标识 slice,一个初始 state 值,以及一个或多个 reducer 函数来定义如何更新 state。创建 slice 后,我们可以导出生成的 Redux action creators 和整个 slice 的 reducer 函数。
/store/modules/counterStore.js
import {createSlice} from '@reduxjs/toolkit'
const counterSlice = createSlice({
// 标识 slice的字符串名称
name:'counter',
// 初始化state
initialState:{
count:0
},
// 修改state的方法(同步方法
reducers:{
increment(state,action){
// 修改时的传参会放在ction.payload属性上
state.count += action.payload
},
decrement(state,action){
state.count -= action.payload
}
}
})
// 从 counterSlice.actions中解构
export const {increment,decrement} = counterSlice.actions
export default counterSlice.reducer
接下来,我们需要从 counter slice 中导入 reducer 函数,并将其添加到我们的 store 中。通过在 reducer 参数中定义一个字段,我们告诉 store 使用这个 slice reducer 函数来处理对该状态的所有更新。
/store/index.js
import { configureStore } from "@reduxjs/toolkit";
// 导入子模块reducer
import counterReducer from "./modules/counterStore";
// 通过configureStore来创建一个store
const store =configureStore({
reducer: {
counter: counterReducer,
},
});
export default store
提供store :
导入我们刚刚创建的 Redux store,在你的 <App>
周围放一个 <Provider>
,然后将 store 作为 prop 传递
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { Provider } from "react-redux";
import store from "./store";
// 将App组件渲染到id为root的DOM元素中
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
读取store中的数据: 使用useSelector
函数
修改store中的数据: 使用useDispatch
函数,并根据需要 dispatch action
import { useDispatch, useSelector } from "react-redux";
import { increment, decrement } from "./store/modules/counterStore";
function App() {
const { count } = useSelector((state) => state.counter);
const dispatch = useDispatch();
return (
<div>
<button onClick={() => dispatch(decrement(1))}>-</button>
{count}
<button onClick={() => dispatch(increment(1))}>+</button>
</div>
);
}
export default App;
异步请求操作:
- 创建store的写法保持不变,配置好同步修改状态的方法
- 单独封装一个函数,在函数内部return一个新函数,在新函数中
2.1 封装异步请求获取数据
2.2 调用同步actionCreater传入异步数据生成一个action对象,并使用dispatch提交
/store/modules/sentenceStore.js
import { createSlice } from "@reduxjs/toolkit";
// 先安装npm i axios
import axios from "axios";
const sentenceSlice = createSlice({
name: "sentence",
initialState: {
sentence: {},
},
reducers: {
setSentence(state, action) {
state.sentence = action.payload;
},
},
});
const { setSentence } = sentenceSlice.actions;
// 获取异步请求数据
const getSentence = () => {
return async (dispatch) => {
const { data } = await axios.get("https://api.xygeng.cn/one");
dispatch(setSentence(data.data));
};
};
export { getSentence };
export default sentenceSlice.reducer;
/store/index.js
import { configureStore } from "@reduxjs/toolkit";
// 导入子模块reducer
import counterReducer from "./modules/counterStore";
import sentenceReducer from "./modules/sentenceStore";
const store = configureStore({
reducer: {
counter: counterReducer,
sentence: sentenceReducer,
},
});
export default store;
3.组件中dispatch的写法保持不变
import { useDispatch, useSelector } from "react-redux";
import { increment, decrement } from "./store/modules/counterStore";
import { getSentence } from "./store/modules/sentenceStore";
import { useEffect } from "react";
function App() {
const { count } = useSelector((state) => state.counter);
const { sentence } = useSelector((state) => state.sentence);
// 通过dispatch触发action,来更新state状态
const dispatch = useDispatch();
// 使用useEffect触发异步请求
useEffect(() => {
dispatch(getSentence());
}, [dispatch]);
return (
<div>
<button onClick={() => dispatch(decrement(1))}>-</button>
{count}
<button onClick={() => dispatch(increment(1))}>+</button>
<div>
{" "}
{sentence.content}--{sentence.name}
</div>
</div>
);
}
export default App;
👻Redux 官网教程
3. Redux调试工具
google商城里搜索: