Computed 必须是纯函数,即只读取响应式数据并返回确定结果,不执行API调用、不修改状态、不依赖非响应式值,以保障缓存有效、响应式链完整和调试清晰。

Computed 必须是纯函数,核心就一条:它只负责“算出一个值”,不干别的事。
什么是纯函数在 computed 里的具体表现
纯函数有两个硬性要求:输入相同,输出一定相同;执行过程不读写外部状态。放到 Vue 的 computed 中,就是:
- 只读取响应式数据(ref、reactive、props等),不修改它们的值
- 不调用 API 请求、不操作 DOM、不修改全局变量或组件外的状态
- 不依赖非响应式外部值,比如 Date.now()、Math.random()、localStorage 等不确定因素
- 所有逻辑只基于当前传入的响应式依赖,不隐藏“暗通道”
为什么不能有副作用
computed 的设计目标是派生状态——回答“我现在是什么样”,不是触发动作——回答“接下来要做什么”。一旦掺入副作用:
- 缓存机制失效:Vue 无法判断“这个值是否真该更新”,可能跳过重计算,也可能错误地重复执行
- 响应式链条断裂:比如在 computed 里改了另一个 ref,这个改动不会被自动追踪为依赖,视图可能不更新
- 调试困难:状态变化原因变得模糊,“是谁改的?”“什么时候改的?”难以定位
- 与 watch 职责混淆:发请求、清定时器、同步外部系统这些事,本该交给 watch 处理
常见踩坑场景和正确写法
下面这些看似方便的操作,都违背纯函数原则:
- ✘ 在 computed 里调用 axios.get() 或 this.$message.success() → 应移到 watch 或 onMounted 中
- ✘ 修改另一个 ref:count.value++ 或 user.status = 'loading' → 这属于副作用,应改用 watch 监听 + 显式赋值
- ✘ 读取非响应式时间:new Date().toISOString() → 若需实时时间,用 ref + setInterval 控制;若只需渲染时快照,可接受,但注意它会让 computed 失去稳定输出
- ✓ 正确示例:fullName = computed(() => `${user.firstName} ${user.lastName}`) —— 只读、无修改、输入决定输出
- ✓ 正确示例:filteredList = computed(() => list.filter(item => item.active)) —— 纯过滤,不改变原 list
不复杂但容易忽略
纯函数不是教条,而是让 computed 安心做它该做的事:可靠、可预测、可缓存。把“要做什么”留给 watch,“点一下就执行”留给 methods,“初始化搭桥”留给生命周期钩子——各司其职,代码才不容易失控。


















