从 Redux 到 Zustand,从 React Context 到 React Server Component,前端开发者在过去五年中见证了一场「数据分发机制」的革命。如果说过去我们用 Redux 是因为“组件通信太麻烦”,那么今天你面对的选择更多、更复杂:你需要选择的不只是“用不用 Store”,而是“数据到底应该分发给谁、在哪分发、怎么分发、谁来负责更新”。
本文将从架构设计的角度,带你深入理解现代 React 应用中的三种核心数据分发模型,并结合真实项目经验,给出以下关键问题的实战答案:
- 为什么 Context 是把“双刃剑”?
- Store 到底是不是“未来架构的毒瘤”?
- Server Component 到底是“性能突破口”还是“维护灾难”?
- 对于大型复杂项目,该如何组合使用它们?
一、Context:轻量,但风险大,慎用
React Context 是最容易被误用的数据分发机制。
✔ 使用门槛低
✘ 一不小心,全组件树都跟着 re-render
常见误区示例:
const UserContext = createContext<User | null>(null);
function App() {
const [user, setUser] = useState(null);
return (
<UserContext.Provider value={user}>
<ComponentTree />
</UserContext.Provider>
);
}
看起来很干净,但只要 user 改变,整个 ComponentTree 中所有用到 useContext(UserContext) 的组件 全部重渲染,哪怕你只改了 user.name。
Context 的本质问题是:它不是“订阅变化”,而是“订阅引用”。
高阶替代策略:
- Context 拆分:不要放整个对象,而是只放需要的字段。
const UserNameContext = createContext<string>('');
const UserAvatarContext = createContext<string>('');
- 配合 useMemo + selector 组合
结合 use-context-selector 可以做到“字段订阅级别”:
const name = useContextSelector(UserContext, c => c.user.name);
二、Store(如 Redux、Zustand、Jotai):结构化、稳定,但也容易滥用
Store 的优点:
- 解耦组件结构与数据结构
- 多个组件共享同一份数据不会有重渲染灾难
- 更适合模块化状态设计和 DevTools 追踪
问题在于:Store 很容易成为“全局状态垃圾场”
尤其是 Redux,很多项目随着时间推移,变成了:
- 全局状态越来越大,无法裁剪
- 状态操作越来越难定位(reducer action 写满一屏)
- 每个改动都要 dispatch -> reducer -> mutation,学习曲线陡峭
Zustand 的轻量方案成为新主流
Zustand 是 Vercel 出的状态管理方案,特点:
- ✅ 无 Provider,无依赖注入
- ✅ 函数式状态管理,无需 reducer
- ✅ 支持 selector,只触发变化字段组件更新
例子:
const useUserStore = create((set) => ({
name: '',
avatar: '',
setName: (name) => set({ name }),
}));
组件中按需订阅:
const name = useUserStore(state => state.name);
对比 Context,这是按需订阅引用,只有 name 变,才更新。
Store 的本质优势:
- 控制 granularity(颗粒度)
- 控制 ownership(所有权)
- 控制 mutation 流程
三、Server Component:不是数据分发机制,但改变了分发时机
Server Component 的革命性在于:把数据处理前置到服务器,而不是客户端再发请求。
示意代码(React 18):
// server component
async function ProductList() {
const products = await fetchProducts(); // 服务端拿数据
return <ul>{products.map(p => <li>{p.name}</li>)}</ul>;
}
这里有几个关键变化:
- ❌ 没有 useEffect
- ❌ 没有 loading 处理
- ✅ 组件 render 之前,数据就准备好了
- ✅ 可以共享数据库连接,不再用浏览器 fetch 接口
这意味着,你根本不需要分发数据给客户端,你直接在组件 render 的时候就有了。
但要注意几点限制:
- Server Component 不支持
useState,useEffect - 想要交互的地方,仍然要用
use client - 数据不可复用:同一个 Server Component 在多次请求中不会保留状态
四、实战模型对比与推荐场景
| 模型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Context | 使用简单,无依赖 | 重渲染不可控,难拆分 | 用户信息、主题、权限等全局常驻数据 |
| Store (Zustand) | 可拆分订阅、逻辑集中、易测试 | 滥用会造成状态碎片、不可组合 | 页面状态、模块数据共享、跨组件业务逻辑 |
| Server Component | 首屏加载快、数据和 UI 合一、免副作用 | 限制较多、调试复杂、只能在 SSR 场景用 | 渲染密集型页面、SEO要求强、首次渲染优化场景 |
五、组合使用才是终极方案
别迷信任何一种方式 —— 现代 React 项目,必须三者并用。
✅ Server Component 用于 SSR 拉取数据,负责页面初始展示
✅ Zustand Store 负责用户交互中的共享状态管理
✅ Context 用于不可变的全局设定,如主题、语言等
实战架构图:
[后端服务]
↓
[Server Component 页面初始渲染]
↓
[Client Component 用 Zustand 管理状态]
↓
[Context 控制非业务相关的全局 UI]
六、真实案例分享:大型电商后台管理系统(350+ 页面)数据架构演进
初版:
- 全部用 Redux
- 所有数据扔进全局 store
- 页面跳转时重复拉取数据 + loading 抖动严重
演进版:
- 页面首次渲染数据由 Server Component 预加载
- 状态类数据(筛选器、分页)走 Zustand store
- 用户信息放 context + session cookie
结果:
- 页面首次渲染速度提升 65%
- 平均 bundle 大小减少 40%
- 用户跳转无感切换,体验提升明显
结语:React 应用的数据分发设计,已经不是“选哪种工具”这么简单了。
你需要考虑:
- 数据出现在哪?
- 要流向谁?
- 需要同步还是异步?
- 需要持久化吗?
- 是否需要响应式?
- 谁有权修改?
只有理解每个机制的本质边界,才能搭建一个既优雅、又高性能、又易维护的数据分发架构。