Redux
什么是Redux
Redux 是一个 JavaScript 状态管理库,主打 “可预测、集中式、单向数据流”。
通俗解释:把整个应用的全局状态放到一个 “大仓库”(Store) 里,用纯函数(Reducer)根据“动作”(Action)去改,组件只负责订阅 & 触发,数据流动完全单向。
Redux诞生背景
- React 本身只解决 “视图层”,当组件层级深、兄弟节点共享、跨页面共享时,“状态提升 + 层层回调” 会让代码变成 “props 地狱”。
- Redux 提供 独立于组件树之外 的 全局数据层。
Redux三大核心概念
| 概念 | 类比 | 说明 |
|---|---|---|
| Store | 大仓库 | 全局状态树,单一数据源 |
| Action | 请假条 | plain object,必须有 type 字段,描述“发生了什么” |
| Reducer | 纯函数出纳 | 接收旧 state + action,返回新 state,无副作用 |
Redux工作流程(单向数据流)
┌─────────────┐
│ 组件触发事件 │
└─────┬───────┘
│ dispatch({ type: 'ADD_TODO', payload: 'Learn Redux' })
▼
┌──────────────┐
│ Action │ (plain object)
└─────┬────────┘
▼
┌──────────────┐
│ Reducer │ (prevState, action) => newState
└─────┬────────┘
▼
┌──────────────┐
│ Store │ 保存新 state
└─────┬────────┘
▼
┌──────────────┐
│ 订阅的组件 │ 自动重新取数 & 渲染
└──────────────┘
Redux示例
import { createStore } from 'redux';
// 1. Reducer:根据动作返回新状态
function counterReducer(state = 0, action) {
switch (action.type) {
case 'INCREMENT': return state + 1;
case 'DECREMENT': return state - 1;
default: return state;
}
}
// 2. 创建仓库
const store = createStore(counterReducer);
// 3. 订阅
store.subscribe(() => console.log('当前值:', store.getState()));
// 4. 触发动作
store.dispatch({ type: 'INCREMENT' }); // 1
store.dispatch({ type: 'INCREMENT' }); // 2
Redux使用场景
用Redux | 不用Redux |
|---|---|
| 多组件、跨页面共享数据 | 局部状态,父子几层以内 |
| 状态更新逻辑复杂、可回溯 | 简单表单、开关 |
| 需要时间旅行调试、快照 | 数据来自服务器即可,无需本地副本 |
| 团队大,需要统一规范 | 小项目、快速原型 |
React-Redux
React-Redux 就是把 Redux 的“中央仓库” 接到 React 组件树 上的官方绑定库。
没有使用React-Redux的情况
需要自己执行如下订阅相关的代码:
store.subscribe(() => {
const state = store.getState();
root.render(<App state={state} dispatch={store.dispatch} />);
});
- 性能差:任何一粒数据变动都整树重新渲染
- 手动传递
dispatch层层钻 - 难以精确订阅局部状态
React-Redux核心能力
| API | 作用 |
|---|---|
<Provider store> | 把 Store 放进 React 上下文,所有组件都能拿到 |
useSelector | Hook:选一块状态,变化才重新渲染组件 |
useDispatch | Hook:拿到 dispatch 函数,随时发 Action |
connect() | HOC(旧API):类组件时代的高阶组件注入 |
React-Redux用法
函数组件
// 1. 入口挂 Provider
import { Provider } from 'react-redux';
import { store } from './store';
root.render(
<Provider store={store}>
<App />
</Provider>
);
// 2. 组件里直接读/写
import { useSelector, useDispatch } from 'react-redux';
function Counter() {
const count = useSelector(state => state.counter); // 订阅片段
const dispatch = useDispatch(); // 拿派发器
return (
<div>
<p>{count}</p>
<button onClick={() => dispatch(increment())}>+1</button>
</div>
);
}
- 精准订阅:
count没变就不重渲染 - 无需
props层层传递:任何深度组件都能直接useSelector
类组件(connect)
import { connect } from 'react-redux';
class Counter extends React.Component {
render() {
const { count, increment } = this.props;
return (
<div>
<p>{count}</p>
<button onClick={increment}>+1</button>
</div>
);
}
}
// 把 state 和 actionCreator 映射成 props
export default connect(
state => ({ count: state.counter }),
{ increment }
)(Counter);
性能优化内置
useSelector默认使用 严格相等 比较,可传入浅比较函数- 订阅粒度到字段级,避免父组件渲染带动子组件
- 批量更新:一次事件循环内多次
dispatch只会触发一次重渲染(React 18 自动 batch)
React-Redux与Redux Toolkit的关系
- Redux Toolkit 负责 “怎么写仓库”(简化语法)
- React-Redux 负责 “怎么连仓库”(让组件用得上)
二者搭配 = 官方推荐现代方案