With the release of the VueJS 3 "Request for Comment" documentation about two weeks ago, Evan You introduced the VueJS function-based API and has set the VueJS community ablaze. These new ideas are still in the "Request for Comments" stage, so they're far from set in stone, but because the RFC introduces such significant changes, I made a quick summary of what you need to know.
NB: All this information and much more is in the RFC, so I do suggest you read that.
Setup
VueJS 3 departs from the option-based API we've grown to love and introduces the setup()
function, which will be where all the magic happens. This function single-handedly sets up the the logic for our component and returns data that's exposed to the template. The option-based API will continue to work even in VueJS 3, but this new function-based API will be the new standard.
For all the functionality we're used to from VueJS like reactive data, computed values, methods and watchers, we import
functions from vue
and use them in our setup()
function. Here's a basic example from the RFC:
<template>
<div>
<span>count is {{ count }}</span>
<span>plusOne is {{ plusOne }}</span>
<button @click="increment">count++</button>
</div>
</template>
<script>
import { value, computed, watch, onMounted } from 'vue'
export default {
setup() {
// reactive state
const count = value(0)
// computed state
const plusOne = computed(() => count.value + 1)
// method
const increment = () => { count.value++ }
// watch
watch(() => count.value * 2, val => {
console.log(`count * 2 is ${val}`)
})
// lifecycle
onMounted(() => {
console.log(`mounted`)
})
// expose bindings on render context
return {
count,
plusOne,
increment
}
}
}
</script>
But why?
If that example doesn't make it clear why this change was introduced, or if it feels like a step back in terms of usability, I understand. I had the same initial reaction and it took me a bit of time to figure out why this change was necessary. The v2.x API is widely loved and is often the reason why people move to VueJS from other frameworks like ReactJS or AngularJS, so a change this drastic seems like a strange idea.
Encapsulation is king
The component API was created in part to make it easier to reuse code across your application. While VueJS is seriously modular and uses components, the current option-based API doesn't allow for an easy extraction of functionality that relates to a single piece of functionality or data. You need to define your data(/state), computed values and methods separately, while they might all be related. This gets confusing when components grow and methods deal with different pieces of data.
This is where the new function-based API comes in. It allows you to extract all code related to a piece of logic and put it together in what they call a "composition function", which returns reactive state. An example given in the RFC uses one of those composition functions to extract the logic of listening to the mouse position:
function useMouse() {
const x = value(0)
const y = value(0)
const update = e => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return { x, y }
}
// in consuming component
const Component = {
setup() {
const { x, y } = useMouse()
return { x, y }
},
template: `<div>{{ x }} {{ y }}</div>`
}
If we compare this to how we would write this functionality in the v2.x API, we can see that the functionality related to using the mouse position is all over the place, where in the v3.x API, it's quite nicely grouped in a singular function:
<template>
<div>
{{ x }} {{ y }}
</div>
</template>
<script>
export default {
data() {
return {
x: 0,
y: 0,
};
},
mounted() {
window.addEventListener('mousemove', this.update);
},
beforeDestroy() {
window.removeEventListener('mousemove', this.update);
},
methods: {
update(e) {
this.x = e.pageX;
this.y = e.pageY;
},
},
};
</script>
And more
Encapsulation isn't the only reason why these changes are useful, so here are two other reasons why this change might be what VueJS needs.
The current option-based API in VueJS has an issue in that it doesn't properly support TypeScript type inference. The proposed changes fix this issue, and achieve full typing support, with TS code looking almost the same as JS code as a cherry on top of an already very useful pie.
VueJS is loved for its extremely small bundle size and this change shrinks that bundle even more. Since function and variable names can be shortened with standard minification (while object/class methods and properties can't), the code simply compresses better.
Thoughts?
Initial reactions to the RFC have been mixed, with some users comparing these changes to React and suggesting VueJS is losing its edge. My first response was far from positive too, but the longer I look at it, the more the encapsulation advantage starts to outweigh the cleanliness of the current API.
What are your thoughts?
Top comments (75)
It feels to me like all the front-end frameworks are constantly trying to scratch an itch that "maybe/probably doesn't exist".
It's all good that everyone is striving to make things better, but these types of changes don't only affect the projects you are still going to do, but also those you've already done. Then a few months later there will be another change, further removing various Vue (or any other FE framework) projects from one another.
In that respect I don't like that the whole development community is the guinea pig for framework development. ie. just as you figure out how a pencil works, someone goes and changes it :)
I guess I want the option to use the current or the next version whenever I want, to infinity. To much to ask?
Couldn't agree more. That's what separated Vue from others, a good common sense one way of building components, where you could hop from one code base to another an find the same approach because the framework had an opinion and consistency.
Now, the setup method will turn common way of doing things to be much like React, where each code base is different and largely a mess. Unfortunately components along don't solve having messy code bases.
I forgot about this aspect, I really liked the idea that most Vue apps were structured the same way! Maybe there was a compromise to be found between the current version and the needs explored by the new one. I don't know, it's too easy to comment from afar
If i had to guess i would say that is because 90% of tutorials begins with "let's install the vue cli and create a project."
One thing Vue got right was give the users freedom to do whatever they want but still provide a recommended way of doing things.
Is like a jedi mind trick, imagine Evan telling you "listen, i won't tell you how to live your life but if you do this thing and use those other things you will find money and happiness."
You will be able to use 2.x API for all 3.x lifecycle and even beyond if community still heavily uses it. Otherwise they are very likely to release a compatibility plugin to let you use 2.x API for as long as you need
yeah great, we can remain in "compatibility" box forever while Vue team only improves for the people adopting the new API.
NO. This should be a branching into a sister project, TypeVue.js, not a 3.x deprecating the original (eventually)
PREACH 🙌🏼
these changes seem more like additions than breaking changes. Like react hooks were
I agree with you definitely.
And when I am saying about "Encapsulation"...in VueJS, there is a great feature called "mixin", and with this, we can make our code more organized or well-structured.
Well said! Agreed
Like you wrote poeple did already compare, it reminds me quite a bit of React's hooks. But that's not a critique, having started with a new React project and having used hooks, I found them to be pretty useful. Vue should not shut themselves away from good concepts just to distinguish itself from other libraries/frameworks. I think incorporating good concepts and making proposals for new ones helps everybody.
The difference is that hooks are in the component and executed on every render. Vue 3’d setup function would only be executed when the component is created.
Hooks is predicated on an assumption that creating functions is cheap, which isn’t always the case, especially in some old and/or embedded environments. This change seems to solve the same problems as hooks but in a more efficient manner.
You're writing single page apps in embedded environments?
Yes. Smart TV apps tend to run in a browser and there isn’t a whole lot of horsepower to work with.
Are you using Vue for building TV apps? I would love to hear your experiences with it if you did!
I was working on the Vue app built for TV last year and it was terrible in terms of performance and general usability. I guess that team that passed it to us was partly to blame because the code was a god damn spaghetti mess.
We're currently building apps for a few TV vendors and React is working fine, the only thing that Vue does better is the animations IMO.
I’m using React, but if it was up to me, I’d probably use Svelte instead.
I’m using React, but if the choice was mine, I’d love to try Svelte instead. It doesn’t use a virtual DOM, so there’s less overhead.
Svelte could be great for embedded since bundle size is a non-issue and no runtime gives performance boost
I have been using Vue for a few years now and have several medium to large projects in production and I have never felt the need for what this change provides. The examples used in the RFC feel like outliers or made to be more common than they actually are.
So you've never used a mixin once on a big project? I really find it hard to believe.
I use mixins all the time. I am not sure what you are referring to. I didn't mention mixins.
That's exactly the point. Mixins are the same composition pattern that 3.x API introduces, but with greater problems, for example :
You can read more on the rendered RFC, but the point is that there can be quite many improvements that the 3.x API can give to applications, especially if they are big
I have never had an issue where two mixins clash and if so it sounds like a design problem more than a problem with the core API/framework and it should be addressed during dev time.
And the times I have been reviewing a component's logic and saw a prop or method being used and cant find it declared in that component I look in the mixins because thats likely the place its coming from.
Again I don't feel like these are common issues I have come across in the 3 years I have been using Vue professionally but that may just be me.
To be honest I hadn't had a problem either but I've never worked on a massively large Vue app either. Maybe they could have just introduced a different way to alias mixins so that methods had a prefix instead of adding a completely new way of using Vue
You can get clashes in the Function API too, if you spread together the return values of several
useXXX()
functions and return them insetup()
.@ju66ernaut It is a design problem, but for example if you have two mixins both fetching a remote API, you need to be extra creative on the
isLoading
property name to avoid clashing, and check every other mixin to be 100% safe. Another problem is that if you use two third party libraries as mixins and they both declare a property, computed, or method with the same name you are pretty much out of options.@amcsi Yes, but with the spread operator you are explicitly merging the keys and somehow take full responsibility of what can potentially clash 😄. With mixins your only option is to rename one of the properties, which can be problematic or even not possible if mixins come from 3rd party libs.
I don't wanna convince you that 3.x API is 100% better than the current, but as you can see the current implementation has some issues that cannot be solved easily
@matteorigon True, my bad.
Me too.. I have SSR and Hybrid applications running on Android and iOS, always was able to go around any limitations I found. I haven't even had any issues with typecasting, what am I doing wrong?? hahaha
Perhaps people writing huge projects that are crapping out because of lack of organization or bad design should investigate using microservices approaches instead?? just a suggestion
Poor organization and project structure plus spaghetti code are so much worse once developers introduce mixins to it. I was working on at least two enterprise apps written in Vue with a bunch of overly complicated mixins. If the code is bad - it can be refactored, project structure can be reorganized, but when you have components with a logic that is really tightly coupled with mixins logic it is hell on earth. In the end, we had to rewrite the whole app...
We should all just go Vanilla. At least I'm trying. Did a lot with React, Angular, Vue, now digin Svelte but I'm tired od learning.
Bein' selfemployed gives me the posibility to choose the stack and that is awesome.
My view maybe a bit simplistic, but I think I have a few points to make. While I've been seriously looking a Svelte 3.0 (compiler, not a framework that's similar in Vue2.0 syntax), I still love the current Vue from top to bottom. However, new complexity "just because" is not what I wanted from Vue - simplicity is. It's not the fact that I will be able to continue to use Vue as I use it now in 3.0. It's really the fact that "NOT EVERYONE USING VUE WILL BE ON THE SAME PAGE" - this can cause fragmentation in the development community, on dev teams and confuse, or even turn off, new Vue adopters seeking to learn the framework. Add the RFC as an optional plug-in, not a core change. Kind of like how we can write JSX within Vue. I'm not looking to defend my remarks - just wanting to state my opinion...period...
This reminds me that sometimes I feel tired that over the years I've been learning so many technologies to do the same exact thing :D
What do you think about svelte?
This isn't exactly correct, and is actually a huge topic of debate on the RFC currently. The current format is not disappearing, it will be offered alongside the new
setup()
function. And it will stay this way if users continue to show that they use the "old" way throughout the lifetime of Vue v3.While that's absolutely true, my point was more to say that the RFC introduces an API that departs from the option-based API, even if that API will continue to be available.
Yes, definitely. With the large amount of misunderstanding on Reddit, HN, and even the RFC thread itself, I'm just trying to help clear any confusion :)
The poor core team seems like they're dealing with a lot during this comment period.
Oh yeah, I (and I'm sure they) appreciate it. I'll update the article to reflect that too :)
I don't think the issue here is solely the RFC, it's the way the Vue team communicates these changes to the community and responds to criticism from people. The way I have seen the Vue team interact with the community and criticism, it's not a good look in my opinion.
Just look at that RFC, people are worried and confused, and I don't think Evan is doing a very good job quelling the fire, to be honest.
One of the biggest reasons people either choose Vue over React or move to it from React was the fact it's cognitively a lot simpler. React gets messy and complex once you start building large apps with it.
All people see with this new RFC is the Vue team making more work for developers and introducing code changes that make Vue look more like React.
Coupled with the fact Evan has been showing a demo of v3 (a secretive prototype not publicly available) and some impressive benchmark numbers, but it seems to me that Vue 3 is nowhere near done and won't be done in 2019.
There seems to be a lot of uncertainty, and the perception to me is they're stuck between a rock and a hard place. They don't know how Vue 3 will look, they want to improve it, but at the same time, they're being held back by their own success (see Angular 1.x).
It raises the question many others are asking: why Vue 3 instead of React?
Maybe the best comment yet. EXACTLY
Thanks for taking the time to write this out. As a beginner, I suspected there were benefits to the change and this helped clear up the pieces that I was missing!
Personally, I kinda like the way
setup()
looks 👀You can start using it right now with vue-function-api in vue2.
Great post! I think people initially missed the benefits of encapsulation and type inference that you explained so well because the syntax looks so different. I love these changes and think they make Vue simpler overall, and the smaller bundle size you mentioned is great. Also I think the Vue team is very responsive to the community and they’ve handled changes to the framework really well in the past, so I don’t think people need to be super worried about backwards compatibility. The fact that this conversation is all happening before even a beta release reflects the Vue team’s proactive approach to communicating about its development.
That's quite a change. I'm all for functional composition, Vue mixins are quite limited.
Was there a real need for it? Probably not as @jaakidup hinted at. Is it better than the current version? Yes.
I wonder how long "support" for Vue 2.x will go on because I don't see companies rewriting overnight.
It's already stated in the RFC post that 2.x API is DEPRECATED, it's just that it will be included as compatibility mode for 3.x not gonna be improved any longer. So any of the updates and benefits the team makes will not come to the people who want to do the 2.x API
I believe support for 2.x would run until 4.x, but none of this is set in stone either
Stefan, I completely agree with your view (pun intended).
To be frank, I don't understand the frustration around these changes. I'm sure it's pretty clear to the devs right now that they'll need keep supporting the old API so I'm not at all afraid that I'll have trouble maintaining my current projects.
The useMouse example is a brilliant enough reason to use the new API in my future projects. Anything that boasts reusability, I'm for it.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.