很多项目前期状态管理都看起来不复杂:
- 一个页面一个请求
- 几个弹窗
- 一两个筛选条件
但只要页面增多、模块变多、用户交互变复杂,很快就会出现熟悉的症状:
- 某个状态在三个组件里分别存一份
- 一个地方改了,另一个地方没同步
- 页面切换回来后数据和 UI 对不上
- 为了修一个小问题,到处加 watch
如果你已经看过 前端框架选型指南、复杂表单逻辑指南、Nuxt 状态管理 Pinia 和 Vue 项目目录如何为 AI 友好,这篇会继续回答一个更实际的问题:页面多了之后,状态到底该怎么管。
一、状态管理最先要做的,不是选库,而是先分类
很多团队一谈状态管理,就先聊 Pinia、Redux 或 Context。但更关键的问题其实是:你到底在管理什么状态。
一个对中小项目很实用的分法是:
| 状态类型 | 例子 | 放在哪里更合适 |
|---|---|---|
| 局部 UI 状态 | 弹窗开关、Tab 激活项 | 组件内部 |
| 页面级状态 | 筛选条件、分页、排序 | 页面或页面级 store |
| 跨页面业务状态 | 用户信息、权限、购物车 | 全局 store |
| 远程数据缓存 | 列表数据、详情数据 | 数据获取层或查询层 |
如果你不先分类,最后最容易发生的事就是“什么都往全局 store 里塞”。
二、不是所有共享都值得进全局 store
判断一个状态该不该全局化,可以先问三个问题:
- 是否被多个页面真正共享
- 是否需要在路由切换后保留
- 是否需要被多个模块同时读写
如果三个答案几乎都是否,那通常说明它不该进全局。
很多项目混乱,不是因为状态太多,而是因为把本地状态也全局化了。
三、内容站和营销站,真正该重视的是“来源单一”
对内容产品、建站后台、营销站来说,状态管理最重要的原则常常不是“多高级”,而是“别有多份真相”。
例如:
- 当前用户信息只能有一个可信来源
- 当前筛选条件不要一半在 URL、一半在 store、一半在组件里
- 表单草稿要么明确放本地,要么明确放 store,不要两边同步猜测
一旦同一个事实被保存了两三份,维护成本会急剧上升。
四、页面多了以后,最常见的状态混乱场景
1. 路由参数和 store 双向打架
比如筛选条件既写在 URL 里,又写在 store 里。刷新后到底以谁为准?返回上一页时又以谁为准?
2. 远程数据被当成本地状态随意拷贝
接口返回的列表数据被复制到多个组件,各自再做转换和筛选,最后谁都不知道原始数据在哪。
3. 临时交互逻辑扩散成长期状态
一个本来只在页面里用一次的状态,被顺手抽到了全局,后面又被别的地方依赖,结果再也删不掉。
五、一个足够稳的状态管理原则:本地优先,跨页再提升
对大多数项目来说,最稳的顺序是:
- 能放组件内部就先放组件内部
- 多个同页组件共享时,再提升到页面级
- 跨页面长期共享时,再进入全局 store
这个顺序的价值在于,你不会为了“以后可能会用到”提前全局化。
六、失败案例:为了统一管理,把所有表单状态都塞进全局 store
这在后台和营销站项目里非常常见。团队觉得“统一管理更规范”,于是登录表单、筛选表单、弹窗表单、编辑页草稿全放进一个大 store。
短期看好像很集中,长期会遇到:
- 页面离开后旧数据残留
- 多个表单互相污染
- 调试时不知道是谁改了哪块状态
根因不是 store 不行,而是把短生命周期状态放到了长生命周期容器里。
七、状态管理检查表
| 检查项 | 合格标准 | 风险信号 |
|---|---|---|
| 单一来源 | 同一事实只有一个主来源 | URL、store、组件三方各存一份 |
| 生命周期匹配 | 短状态放短容器,长状态放长容器 | 临时状态长期残留 |
| 共享边界清楚 | 只有跨页共享才进全局 | 本地状态也全局化 |
| 数据职责清楚 | 远程数据与 UI 状态分开 | 所有数据都混在一起 |
八、上线前检查清单
- 当前项目是否区分了局部 UI 状态、页面状态和全局业务状态
- 同一个关键数据是否只有一个可信来源
- 是否避免把短生命周期表单状态滥用到全局 store
- URL 参数、页面状态和远程数据是否边界清楚
- 页面切换、刷新、返回时状态是否符合预期
结语
状态管理真正的目标,不是把数据集中起来,而是让数据关系更清楚。页面一多以后,能不能长期维护,往往就取决于你有没有坚持“本地优先、来源单一、边界清楚”这几个基本原则。


