← 返回资讯
陈默
AI 行业分析师
已审核

Vue Function-based API RFC

2019年底,我窝在工位上啃着面包,刷到Vue 3的Function-based API RFC。

Vue Function-based API RFC

Vue Function-based API RFC


我花了三天时间死磕Vue Function-based API,最后决定这么用——真香,但别急着全盘重写!

2019年那个深夜,我差点以为Vue要变天

你猜怎么着?

2019年底,我窝在工位上啃着面包,刷到Vue 3的Function-based API RFC。

第一反应——这啥玩意儿?!

第二反应——完了,Vue要变成React了?

那会儿网上吵翻了天。有人说这是Vue自废武功,有人大喊“抄React抄得真香”,还有一堆人在评论区互骂。

我呢,有个臭毛病:光看理论睡不着,必须上手怼一遍。

于是那个周末,我翻出了公司后台管理系统里一个不疼不痒的功能模块,装上了刚出炉的 vue-function-api(后来改名 composition-api),版本号记得死死的:vue-function-api@2.0.1,配的是我那老掉牙的 Vue 2.5.17 项目。

然后就是三天的心跳、踩坑、真香、再踩坑、再真香……


说到Vue 2的逻辑复用,我真是受够了!

你想想啊,我们团队维护着一个后台系统,上百个业务组件,各种列表、表单、详情页。

两个组件都要做搜索、分页、排序,还得在页面一打开就自动拉数据。

最开始,我用 Mixin

三个Mixin一混,模板里的 search 方法到底是谁提供的?查半天定位累成狗。

最离谱的一次:同事写了个mixin叫 listHandler,我写了个 listHandle——少了个r。两个mixin一起用,直接冲突,整个页面崩了。

created 钩子里十几个Mixin的执行顺序?基本靠猜,猜不中就花半天调试。

后来试过 HOCRenderless 组件

HOC包装一层组件实例,性能还行,但props一层层往下传,调试时得翻好几层组件结构,脑子不够用。

Renderless更尴尬:为了传递一个函数,slot scope里塞满了 {{ slotProps }},代码一多连自己都看晕了,改个逻辑得从头捋到尾。

所以当我看到RFC里那句“逻辑组合与复用”时,第一反应就是——

救星终于来了!


我的第一个 setup 函数,清爽到飞起

装好插件后,我最想验证一件事:能不能把原来一个列表页的 mounteddatamethods 全都塞进一个 setup 里?

代码长这样:

JAVASCRIPT
import { value, computed, watch, onMounted } from 'vue-function-api'

export default {
 name: 'UserList',
 props: ['query'],
 setup(props, ctx) {
 const list = value([])
 const loading = value(false)
 const currentPage = value(1)

 const totalPages = computed(() => Math.ceil(list.value.length / 10))

 const fetchList = async () => {
 loading.value = true
 const res = await api.getUsers({ page: currentPage.value })
 list.value = res.data
 loading.value = false
 }

 watch(() => props.query, (newQuery) => {
 currentPage.value = 1
 fetchList()
 })

 onMounted(fetchList)

 return {
 list,
 loading,
 currentPage,
 totalPages,
 fetchList
 }
 }
}

第一眼——太清爽了!

所有和列表相关的逻辑都待在一个函数里,不再分散到 datamethodscreated 里乱跑。

但跑起来……呵呵,坑来了。


踩坑实录:每个坑我都替你跳了

1. `.value` 这个点,真的烦

这个坑估计每个用过Composition API的人都被绊过。

value(0) 返回的是一个带 .value 属性的响应式对象。在 template 里直接用 {{ count }} 没问题,但 在 setup 内部,你必须写 count.value 才能读写

我写 fetchList 时直接写了 currentPage++,结果页面死活翻不动——“你改了啥?class啊?不是响应式?拜拜了您嘞。”

改成 currentPage.value++ 就好了。

坦白说,每次多敲几个字符—— .value ——都挺烦的。但后来我想通了:这是Vue团队在设计上对原生类型的妥协方案。到了Vue 3,ref 也是一样的设计,不过加上了 isRefunref 辅助函数,稍微好一丢丢。

2. setup 里没有 this,我的$router呢?

以前写 methods 时,我天天用 this.$routerthis.$store 这些实例属性,顺手得不行。

但到了 setup 里,thisundefined!第一次用我就懵了:我要怎么拿到路由?怎么拿vuex?

后来得用 getCurrentInstance() 或者从参数里解构。

比如在 vue-function-api 里:

JAVASCRIPT
import { getContext } from 'vue-function-api'

setup(props, ctx) {
 const { $router, $store } = getContext()
}

但注意—— getContext 只能在 setup 中同步调用。你在定时器里调它?直接报错!

跟React Hooks的规则一模一样:不能条件调用、不能异步调用

3. 生命周期钩子的坑:想偷偷懒?没门!

onMountedonBeforeUnmount 这些函数,必须直接在 setup 顶层同步注册

不能包在 if 里,不能放在 setTimeout 里。

一开始我想按条件注册 onBeforeUnmount ——比如说,用户是管理员才在离开时清理资源。结果Vue直接抛出:onMounted is called when there is no active component instance

被教育了。后来我改成通过一个 watch 来决定是否清理。

4. 类型推导,这个真香

这一点我必须要夸!

我们项目里有一部分业务逻辑用 TypeScript 重写过,但 Vue 2 搭配 TypeScript 的体验,谁用谁知道:装饰器满天飞,Vue.extend 写起来像受刑。

而 Composition API 天然支持类型推导——ref('') 一写,整个链路的类型都稳了。

我用 vue-function-api 时试了一下 computed 的返回类型和 ref 的组合,比 data 那种对象字面量类型推导准得多。妈妈再也不用担心我类型写错了。


和 React Hooks 的对比:它们根本不是一个物种

测试完后,很多同事跑来问我:“这不就是 React Hooks 的 copy 吗?那为啥不用 React?”

我每次都得跟他们解释一遍——用过才知道,差远了

先看对比:

| 对比维度 | React Hooks | Vue Composition API |

|---------|------------|-------------------|

| 状态创建 | useState 返回 [value, setter] | ref()reactive() 返回响应式对象 |

| 状态更新 | 调用 setter 触发重新渲染 | 直接赋值 .value = newVal,自动触发 |

| 副作用管理 | useEffect,需要手动声明依赖 | watchwatchEffect,自动追踪依赖 |

| 渲染机制 | 每次状态更新都重新执行整个函数组件 | setup 只执行一次,后续通过代理的 getter/setter 追踪 |

| 与模板关系 | JSX 嵌入逻辑 | 模板依然单独声明,逻辑在 setup 中返回 |

| 独立使用能力 | 模式可移植,但需要宿主框架重新实现 | 响应式 API(reactivecomputed 等)可直接作为状态管理库使用 |

看到区别没?

React Hooks 的本质是 基于函数执行顺序的闭包机制。每次渲染都重新执行所有Hooks,如果依赖数组写错,你就会拿到闭包里的旧值,bug莫名其妙。所以要记住 useCallbackuseMemo 的依赖项,不然就等着哭。

而Vue的Composition API呢? 基于响应式代理。setup只执行一次,后续所有变更靠 Proxy 的 getter/setter 追踪。你不需要担心闭包过期——每读取 count.value,都是最新的值。写起来心理负担小很多。

尤大在说过一句话我特别认同:Vue 走的是 value 增强 路线,React 是 function 增强 路线。

前者把值变成响应式的,随取随用;后者每次渲染都生成一个新的快照,依赖一致性需要手动保障。

一个省心,一个要靠头脑清醒。你选哪个?


真正的宝贝不是 setup,是 Reactivity API

我花了2天时间,把 reactivecomputedwatchEffect 抽出来,写了一个独立的 store:

JAVASCRIPT
// store.js
import { reactive, computed } from 'vue-function-api'

const state = reactive({
 users: [],
 page: 1
})

export function useStore() {
 const total = computed(() => state.users.length)
 const load = (page) => fetch(`/api/users?page=${page}`).then(r => r.json()).then(data => state.users = data)
 return { state, total, load }
}

然后在任何组件里 import 这个函数,直接用。不需要 Vuex,不需要 Provider。

reactive 返回的对象本身是响应式的,改了自动触发关联组件的更新。

这比 React Hooks + Context 的方案轻了不是一星半点,而且不需要任何高阶组件包裹。

这就是RFC里说的 Advanced Reactivity API ——它脱离了组件的约束,可以作为独立的响应式数据流方案。理论上,你可以把它用在任何JS环境里,配合小程序或Node.js做状态存储,都没问题。

我用它写过一个小玩具,像 Cycle.js 一样用 watchEffectmap 做数据流编排。居然跑通了!

不过那是另一个故事了。


回到现实:项目里到底该不该用?

你现在问我:2025年了,Vue 3 早已是正式版,还值不值得用?

我的答案:如果你还在用 Vue 2,而且不想一下子跳 Vue 3,可以用 @vue/composition-api 插件先过渡。vue@2.7 已经内置了 Composition API,官方维护,稳得很。

对已有项目,只在新模块里用,千万不要大规模重构老代码。Mixin 虽然有毛病,但稳定运行的项目,没必要为了新 API 而重写。你的业务不会因为换了个写法就变好。

新项目优先选 Vue 3 + Composition API,因为:

我个人的习惯是:把复杂业务组件的逻辑提取到 useXxx 函数里。

比如我写个采购订单组件:

然后组件里就变成了:

JAVASCRIPT
setup() {
 const { form, rules, onSubmit } = useForm(props)
 const { list, loadMore } = useList(props)
 const { print } = usePrint()
 return { form, rules, onSubmit, list, loadMore, print }
}

读组件就像读目录一样清楚,每个 hook 的职责一目了然。


最后说几句真心话

Vue 3 的 Composition API 不是银弹。

它依然要和 template 配合,不像 JSX 那样完全函数化。对于简单的组件,setup 甚至比 data + methods 写起来还啰嗦——一个按钮加个数字计数器,写 setup 确实比 Options API 多几行。

但一旦组件逻辑复杂到需要复用或拆解,它的好处就出来了,你会忍不住喊一声:真香。

我对这个 RFC 的评价是:方向对了,实现也不错,该踩的坑我也替你们踩了。

关于 RFC 本身,当年那篇 vue-function-api 已经归档成了历史。现在最新的官方文档在 composition-api.vuejs.org,内容做了大量修订。当初我初读 RFC 时觉得某些 API 设计有争议(比如 value vs ref 的命名,还有 watch 的参数顺序),到正式版都改了。所以,RFC 的阶段就是给你提意见的,别一看到提案就觉得是最终形态。

慢慢来,我最开始也只敢拿一个模块试水。路是一步步走的,但方向对了,跑起来才带劲儿!


如果你觉得 Vue 2 的 mixin 让人头疼,Composition API 是你一直在等的解药。但别激动到把整个项目重写,谨慎地试试水,你会感谢那个周末加班的自己。

585
9756 阅读
2 评论
分享
链接已复制
编辑说明

本文由 MakeSense 编辑团队撰写并审核。文中引用的数据和观点均经过交叉验证,如有疏漏欢迎在评论区指正。最后更新:2026年06月24日 22:39

陈默

AI 行业分析师

前某大厂 AI 实验室研究员,关注大模型技术演进和商业化落地。写过 200+ 篇行业分析,擅长从产品视角拆解技术趋势。

读者评论 2

数据分析师 昨天
数据引用很扎实,建议补充一下近三个月的最新数据。
回复 点赞 (9)
产品经理阿杰 4天前
从产品角度看,这个方向确实有机会,但商业化路径还需要验证。
回复 点赞 (15)