什么是 redux?它的核心概念是什么?
redux 是一个状态管理库,它将项目中的数据集中的管理在一个 Store 里,使得存取都非常简单。 它的核心概念包括:
单一数据源(Store):Redux 设计中整个应用的状态存储在一个单一的 Store 中,使得状态管理集中且易于追踪。
Actions:Actions 是把数据从应用传到 Store 的简单对象,描述了应用中发生的事情。每个 Action 都有一个必须的 type 属性,用来定义 Action 的类型。
Reducers:Reducers 是纯函数,接收旧的 state 和一个 Action,然后返回一个新的 state,以此来响应 Action,更新应用状态。Reducers 保持无副作用,确保相同输入始终得到相同输出。
State:Redux 中的状态(State)是只读的,要改变状态,必须 dispatch 一个 Action,通过 对应的 Reducer 来生成新的状态。
redux 的工作流程是什么?
-
Action 发起:
- 用户与应用交互(如点击按钮)时,触发一个动作(Action)。
- Action 是一个普通的 JavaScript 对象,包含一个必需的
type
属性,用来描述发生了什么事情,还可以携带其他数据(payload)。
-
Action Dispatch(派发):
- 通过调用 Redux Store 的
dispatch
方法,将 Action 发送到 Store。 dispatch
方法是修改应用状态的唯一途径。
- 通过调用 Redux Store 的
-
Reducer 处理:
- Store 收到 Action 后,会将它转发给 Reducer 函数。
- Reducer 是一个纯函数,接受当前的 State 和收到的 Action 作为参数,基于这两个输入计算并返回新的 State。
- Reducer 必须是无副作用的,给定相同输入应始终产生相同的输出。
- 如果有多个 Reducer,Redux 会使用
combineReducers
函数将它们组合成一个大的 Reducer 树,每个子 Reducer 负责管理状态树的一部分。
-
State 更新与 View 重新渲染:
- Store 收到 Reducer 返回的新 State 后,会更新自身的 State,并触发一个更新通知。
- 任何订阅了 Store 更新的组件(通过 React-Redux 的
connect
或useSelector
等)都会收到通知,然后可以根据新的 State 重新渲染视图。 - 这个过程确保了视图总是反映了最新的应用状态。
使用步骤 Demo 演示。
// 入口文件
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import store from "./store";
import { Provider } from "react-redux";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
);
// store/index.js
import { configureStore } from "@reduxjs/toolkit";
// 导入子模块
import counterReducer from "./modules/counterStore";
// 合并成新的模块
const store = configureStore({
reducer: {
// counter(合并store时的命名空间):counterReducer:(对应的子store里的方法和数据)
counter: counterReducer,
// ...
},
});
export default store;
// store/modules/counterStore.js
import { createSlice } from "@reduxjs/toolkit";
const counterStore = createSlice({
// 命名空间
name: "counter",
// 初始状态
initialState: {
count: 666,
channelList: [],
},
// 同步方法
reducers: {
inscrement(state) {
state.count += 1;
},
decrement(state) {
state.count -= 1;
},
addToNumber(state, action) {
state.count += action.payload;
},
setChannels(state, action) {
state.channelList = action.payload;
},
},
});
// 解构方法
const { inscrement, decrement, addToNumber, setChannels } =
counterStore.actions;
const fetchChannels = () => {
return async (dispatch) => {
const res = await fetch("http://www.********.com/api/channels");
const data = await res.json();
dispatch(setChannels(data.data.channels));
};
};
// 获取reducers
const reducer = counterStore.reducer;
export { inscrement, decrement, addToNumber, fetchChannels };
export default reducer;
// App.js
import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
// ----- // 导入store中的方法 start -----
import {
inscrement,
decrement,
addToNumber,
fetchChannels,
} from "./store/modules/counterStore";
// ----- 导入store中的方法 end -----
export default function App() {
// ----- 获取store数据 start-----
const { count, channelList } = useSelector((state) => state.counter);
// ----- 获取store数据 end-----
// 获取 dispatch
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchChannels());
}, [dispatch]);
return (
<div>
<button onClick={() => dispatch(inscrement())}>加一</button>
<button onClick={() => dispatch(decrement())}>减一</button>
<button onClick={() => dispatch(addToNumber(1000))}>加十</button>
<div>
<ul>
{channelList.slice(0, 5).map((item, index) => {
return <li key={item.id}>{item.name}</li>;
})}
</ul>
</div>
</div>
);
}