Vue Function-based API RFC
Vue Function-based API RFC (English)
I Spent 3 Days Wrestling with Vue's Function-based API – Here's What I Finally Decided: It's Actually Great, But Don't Rewrite Everything Yet!
That Late Night in 2019, I Almost Thought Vue Was Going to Change Beyond Recognition
Guess what?
Toward the end of 2019, I was huddled at my desk eating bread when I stumbled upon the RFC for Vue 3's Function-based API.
My first thought—What in the world is this?!
Second thought—Oh no, Vue is turning into React?
The internet was exploding. Some people said Vue was shooting itself in the foot, others screamed "they're shamelessly copying React and it's great," and a bunch of users were cursing each other in the comments.
I've got a bad habit: I can't sleep just reading theory. I have to try it out myself.
So that weekend, I dug out a low-stakes feature module from our company's admin system, installed the fresh vue-function-api (later renamed composition-api), and I still remember the version number: vue-function-api@2.0.1, paired with my ancient Vue 2.5.17 project.
Then came three days of excitement, pitfalls, "oh this is good," more pitfalls, and more "oh this is good" again…
When It Comes to Logic Reuse in Vue 2, I Was So Fed Up!
Think about it: our team maintains an admin system with hundreds of business components. Lists, forms, detail pages—you name it.
Two components both need searching, pagination, sorting, and automatic data fetching when the page loads.
At first, I used Mixin.
Mix three mixins together, and who provided the search method in the template? You have to hunt forever.
The worst case: a colleague wrote a mixin called listHandler, and I wrote listHandle—missing an 'r'. When both mixins were used together, they conflicted directly, and the whole page crashed.
The order in which a dozen mixins execute in the created hook? Basically guesswork, and half a day debugging if you guessed wrong.
Later I tried HOC and Renderless Components.
HOC wraps a layer of component instance—performance is okay, but props get passed down layer by layer, and when debugging you have to dig through several layers of component structure. My brain couldn't keep up.
Renderless was even more awkward: just to pass a function, the slot scope was packed with {{ slotProps }}, and when the code grew, even I got dizzy—changing one bit of logic meant tracing through the whole thing.
So when I read the RFC's line about "logic composition and reuse," my first reaction was—
Finally, a savior!
My First `setup` Function – So Clean It Made Me Smile
After installing the plugin, I wanted to verify one thing: could I cram the mounted, data, and methods of an existing list page all into a single setup?
The code looked like this:
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
}
}
}
First glance—so clean!
All the logic related to the list sits in one function, no longer scattered across data, methods, created, etc.
But when I ran it… well, the pitfalls came.
Pitfall Log: I Jumped into Every One So You Don't Have To
1. That `.value` Thing – Really Annoying
I bet everyone who's used Composition API has stumbled on this.
value(0) returns a reactive object with a .value property. Using {{ count }} in templates is fine, but inside setup, you must write count.value to read or write.
When I wrote fetchList, I directly wrote currentPage++, and the page just wouldn't turn—“What did you change? A class? Not reactive? Goodbye.”
Changing it to currentPage.value++ fixed it.
Honestly, every time I type those extra characters—.value—it's a bit annoying. But later I made peace with it: this was Vue's team design compromise for primitive types. In Vue 3, ref works the same way, though they added helper functions like isRef and unref to make it a bit easier.
2. No `this` in `setup` – Where's My `$router`?
Back when I wrote methods, I used this.$router, this.$store, and other instance properties all the time. So convenient.
But inside setup, this is undefined! The first time I tried, I was stunned: how do I access the router? How do I get vuex?
I had to use getCurrentInstance() or destructure from the arguments.
For example, in vue-function-api:
import { getContext } from 'vue-function-api'
setup(props, ctx) {
const { $router, $store } = getContext()
}
But note— getContext must be called synchronously inside setup. Calling it inside a timer? Direct error!
It's exactly like the rules for React Hooks: no conditional calls, no async calls.
3. Lifecycle Hook Gotchas – Trying to Cut Corners? No Way!
Functions like onMounted, onBeforeUnmount must be registered synchronously at the top level of setup.
You can't wrap them in an if, can't put them inside setTimeout.
Originally I wanted to conditionally register onBeforeUnmount—say, only clean up resources on leaving if the user is an admin. Vue immediately threw: onMounted is called when there is no active component instance.
Lesson learned. Later I changed to using a watch to decide whether to clean up.
4. Type Inference – This One's Truly Nice
I have to praise this!
Some of our project's business logic was rewritten in TypeScript, but the experience of Vue 2 with TypeScript—anyone who's used it knows: decorators everywhere, and writing Vue.extend feels like torture.
But Composition API naturally supports type inference—just write ref and the whole chain's types are solid.
When I tried it with vue-function-api, the combination of computed return types and ref was much
Cael Lee
Full-stack developer with 8+ years of experience. Currently building AI-powered developer tools. I've tested 20+ AI API providers and coding assistants.