Composition API is one of the biggest new features in Vue 3. In this talk, I will explain what is it and how to use Composition API for code abstraction and reuse.
Composition API: a Quick overVue
AI Generated Video Summary
The Talk introduces the composition API in Vue 3 as a better option for composing reusable features compared to mixins and scope slots. It explains how to abstract search functionality using the composition API and demonstrates the creation of searchQuery and searchResultsQuery objects. The Talk also covers running breed search in the mounted hook, sorting results using computed properties, and the benefits of the composition API in terms of code organization and reusability. It concludes by mentioning the upcoming release of Vue 3 and the advantages of the composition API.
1. Introduction to Vue 3 Composition API
Today we are going to speak about one important feature of Vue 3, which is a composition API. The new composition API is purely additive, so you won't need to rewrite all your components written with the Options API.
Hi everyone! Today we are going to speak about one important feature of Vue 3 will bring, which is a composition API. But before we start speaking about it, I want to give you an important warning. When we first introduced this new API, we made a huge mistake. We were speaking about deprecating some options from the old API and people understood it slightly differently than we want. You can see some quotes from Reddit saying like, do I need to write all my components to the new syntax? And I want to say, no, please don't be like this. The new composition API is purely additive. You won't need to write all your good components written with Options API to this new syntax.
2. The Need for a New Vue.js API
After introducing myself as Natalia, a Vue.js core team member and front-end engineer at GitLab, I explained the need for a new API in Vue.js version 3. Using the example of CatSplorer, an app for searching and sorting cat breeds, I showed how the current code is fragmented and difficult to maintain. I then introduced mixings as a way to compose reusable features, but highlighted their limitations in terms of reusability and customization.
And after this warning, now I'm safe and I can introduce myself. My name is Natalia and I'm Vue.js core team member. I care mostly about Vue documentation. I work as a staff front end engineer at GitLab, and I'm also a Google Developer expert in web technologies.
So why do we need this new API? Is there anything we were really lacking in Vue.js version 2? Let's take a look at this small application. Please meet CatSplorer, an app to search and sort cat breeds. As you can see, we have two features here. First is searching. Second is sorting with different parameters.
In the application code, this will look like this. So, this code belongs to search. We have some part of the reactive state responsible for searching, and we have a method to run this search. And of course we have something for sorting. Again, we have some reactive data, and we have some computed properties to calculate these sorted results.
If we take a look at the component code, we will see how these two features are divided in it. So here is a code that belongs to search, and here is a code for sorting. And as you can see, the logic is pretty much fragmented here. Imagine I'm a developer who needs to fix the search, and I need to follow this logic and I will be jumping from data to method and vice versa. So do we have a way to compose this reusable features and abstract them somehow?
So the first option in the current API are mixings. Mixing is an object that can contain any set of component properties like data methods, computed lifecycle hooks. And when mixing is included into the component, these properties are mixed in with component properties. Sometimes component can override mixing properties if the there is a name collision. Sometimes they are merged together like in the case of lifecycle hooks. But basically you need to understand there's just mixing in properties from mixing to the components. So here is a mixing for the search, and here is a sorting mixing that includes only properties we need for sorting. And if we take a look at this, this is way less fragmented, right? And then we just include this mixing as a component at the bottom. But there are some problems about mixing. First of all, they're not really reusable. If you did pay attention to the search mixing, you saw this access call. So we are not able to customize our search.
3. Abstracting Search to Composition API
We cannot pass the endpoint to the mixing and replacing Axios with CraftQL calls is conflict prone. Mixing properties can be overwritten by component ones, making it hard to track their source. Another option is scope slots, which allow child components to expose their scope to content in the slot. However, data and methods exposed to the scope slot can only be used within it, making it less flexible and performant. Vue 3 introduces the composition API as a better option, and we will demonstrate how to abstract these features into it.
We will always use the same endpoint because this is defined in the mixing. We cannot pass even the endpoint there, not speaking about replacing about replacing Axios with some kind of CraftQL calls. Conflict prone.
As I mentioned, mixing properties could be overwritten by component ones. In this case, we can't be sure that everything we exposed from the mixing safely landed in the component and unclear source. If you've ever used mixins, you know how hard it's to track which method comes from which mixing, especially if you have multiple swarms, multiple ones in the component.
We have another option, which is scope slots. I won't go into deep details, but basically in view, component can have slots, and we can place anything in this slot, like text, HTML, other components, and all this content will belong to parent scope. When we speak about scope slots, we mean that child component, in this case, it's generic search, can expose a part of its scope like a data, methods, whatever we want, to the content in the slot. So you can think about component with a scope slot, like a component that contains some logic, not a template in this case, like a wrapper that forms some operations and exposes data and methods to its content.
It looks much better because as you can see, we can pass run breed search there. So we are not setting it up to static access call, but this is not flexible. First of all, data methods that are exposed to the scope slot are exposed only to the scope slot. We cannot reuse any kind of exposed data in other places in the template or in the options API or whatever else outside of the slot, and this is less performant because in this case generic search is still a view component. This is a view instance and you need to mount this view instance to make it work. So do we have any other options in Vue 3? Yes. This is a new composition API, and I want to show you how does it work and how we can abstract these two features into the composition API. That's why we're switching to live demo. Wish me some luck.
So here is a code for the search and sorting, and let's start with abstracting search to its own composable. Let's go to composables folder and create a new file named search.js. And we want to export a function from here. Let's name it useSearch. And let's take a look. What do we have for search? First of all, we have two of these reactive properties, which are query and results. And we want to abstract them completely from this component. So let's create our first reactive property called searchQuery. And this will be a ref of an empty string. Empty string is an initial value of this search query here, and what ref does under the hood. In fact, we are creating a search query, which will be equal to an object with value of an empty string.
4. Creating SearchQuery and SearchResultsQuery
This part explains how the searchQuery and searchResultsQuery objects are created using the ref function. The runBreedSearch method is introduced as a way to abstract the logic of the API call. It accepts a function as a parameter and calls it with the query value. The response is then used to set the value of search results.
And this object is reactive, thanks to ref. So any changes to searchQuery.value will be reactive. We need also to create a searchResultsQuery, which is a ref of an empty array. And of course we need some method. Let's call it runBreedSearch. And this, I'm sorry, my typing is really bad today. And this is a function. And what do we want to do here? So we want to pass something to run because we don't want to make this access call static, we want to abstract the logic. So this code will accept some function, let's say getResults. And it will call getResults. And we want to have our query as a parameter here. But remember, this is a ref. So when we are referring to the ref inside of the composition function, we need to remember about value. And then we have some response and we want to set search results value to this response.
5. Running Breed Search in Mounted Hook
We want to run breed search in the mounted hook. We return search query, search results, and run breed search from the composition function. The setup option is introduced, allowing access to the setup's returned values in both templates and the options API. However, data properties and computed cannot be referred to in the setup. The use search method is used, passing a callback and recalculating the endpoint based on the query. Finally, the breed search, breed endpoint, and methods and mounted section are removed.
What else do we have for search? We abstracted on breed search. Oh, we have mounted. So we want to run breed search in mounted hook. This can be also abstracted here. And we want to run, run breed search. That's basically it. That's basically it.
Now we need to return whatever we want to use in the component from the composition function. So we're returning search query and search results in this case. And of course we need to return run breed search. Now we can start using this in the component. First, obviously we need to import our use search. From the composables.
And now we're introducing a new option in the component which is setup. In terms of life cycle hooks, setup will be involved before created hook. And we can access the things returned from the setup in both the templates and options API. So here, but we can't refer to data properties or compute it in the setup because when setup is running, we don't have data or computed. So let's use our use search method here. I want to have search query, search results, and run breed search here. And I need to pass a method here like a callback. So this callback will accept a query parameter, we're passing it here from search query value. And we need to recalculate endpoint. We cannot refer to this computed because setup is running before computed exist. So I will simply calculate it based on query. And then I want to run my access call. Here I will simply use an endpoint I've just defined. Here we should use our best query from search query value. And in a response I just want to filter data because saving logic will go to the composable. Now I can get rid of breed search, breed endpoint, and the whole methods and mounted section. And I need to fix my templates slightly.
6. Working on Sorting and Selected Option Index
So this should be fine. We have our cats. Let's try the search. Great, search is abstracted. Now, let's work on sorting. We need options, active property, results, items, selected option index, and sorted results.
So this should be fine. And we also have these breed search results. This will be replaced the search results. Important moment. You can see I'm not using search results value here as well as I'm not using search query value here because when you use anything returned from the setup in the template or options API, ref will be automatically unwrapped for you. You don't need to care about value in the template.
So let's take a look at our application. And this all happened because I simply forgot to return everything from the setup. And trust me, I do this every single time. And I believe this is one of the cons of the new API because you need to explicitly return everything from the setup option. Here we go. And now, as you can see, we have our cats. Let's try to see if search works. It does. We didn't break sorting. No, we didn't. So, great, search is abstracted.
Now, let's try to work on sorting. I will create one more file. In fact, you can store all your composables in one file, but I just want to make it more visible. And I want to export function, use sorting here. So, what do we need for sorting? Let's try to take a look. First of all, we have options, and I don't want to hard-code them to sorting, I just want to pass them there. We have our active property for selected option, and this makes sense to be abstracted because this is an internal logic of sorting. And we have results. Obviously, results should be in sorting as well. But as you can see, we are sorting some items, and I don't want these items to be hard-coded, again, I just want to pass them to sorting. So we want to have our options and items. And we need to create selected option index, which is a reactive property with a default value of zero. And we need our sorted results.
7. Sorting Results with Computed
As you can see, sorted results are computed property and will be recalculated if their reactive dependency changes. We can use computed in the composition API by importing them from the view. The logic is copied and slightly fixed. We don't have results sorting, only options, selected, and selected option index values. We use items as a trick by passing a computed property, and we return selected option index and sorted results from the setup option.
As you can see, sorted results are computed property, which means they will be recalculated if their reactive dependency change. We can use computed in the composition API as well. We just need to import them from the view. And in this case, computed will accept a callback. I will copy paste the logic from here and fix it slightly.
We don't have results sorting, we just have options. We have our selected, we have our selected option index value. Don't forget this is a ref. And here we will use our items. Here is a trick. I know I will pass a computed property as items here and computed is a ref internally. So here I will need to use items value. And I need to return everything I want from date sorting. So selected option index and sorted result. Oh God. Sorted results.
Now let's go back and try to change our component as well. First of all, I want abstract options to a small constant, let's call it sorting options. And I need to return these options from the setup as well, because I will use them in the template. Now let's import our used sorting from our Composables. And let's create more constants here. So we will have selected option index and sorted results from use search. And I will just move a constant declaration a bit higher because I will need it in my use sorting. So first parameter is sorting options. And second, as I already mentioned, is computed because I need to track any changes in my search results. And when they change, I want to recalculate this computed. In this case, I will return search results value. Remember, search results is a ref itself. And I want to return selected option index as well as sorted results from my setup option. I can remove data now as well as computed, and I need to change my template as well.
8. Sorting and Selected Option Index
Here we will have sorting and selected option index. Sorting and search are working. Composition API can be used independently or in combination with the options API. Follow the link or Google Composition API RFC for more information. Check out the repository with starting and finished code. Thanks for joining us and for the positive feedback.
So here I will have sorting, oh god. Sorry, I'm really bad when I'm typing something when do live coding. And here we will have selected option index.
So let's take a look at the application again. Oh, of course, order by is not defined because I forgot to move this part of the logic from the template to the composable. And right now we fixed it, sorting works. Search works. Great, just a few mistakes during live coding and we are here.
So basically we just learned we can use Composition API independently. I read on the whole component or in the combination with a old good options API as well. If you want to learn a bit more about the Composition API, please follow this link or just Google for Composition API RFC. There is the most full source of information about the Composition API so far. And I also created this small repository you can play with. Please target view three branches. There is a branch with a starting code and with a finished code as well. And thank you.
Hey Natalia. Thanks for joining us and for this really clear talk. First comments. I actually got a message while you were speaking from a colleague of mine. Hey Dean, how are you doing? That he was thought, he has such a relaxed voice and that really helped him follow along. So he was in the moment with you. So this is something given. So I don't know if you can thank him for it, but yeah, he liked it. So, so did I, by the way.
I want to remind everyone that if I don't have time to answer your quest or ask questions to Natalia. Natalia will go to a Zoom room where you can continue to discussion about the Composition API or anything else future related with Natalia. And the link is below the player on the website in the timeline. You can just click on her Zoom room. Let's go to the first question and it's an easy one.
9. Benefits of Composition API
The composition API is not recommended if you don't have features to abstract and reuse, or if your team is already familiar with the option API. However, you can evaluate the features that need to be reused and gradually add them with the composition API. The new composition API in Vue 3 allows you to combine logical code in one place, similar to React hooks, and create custom hooks for reusability. It also simplifies the development of Vue plugins by allowing you to export functions and use provide inject within the Vue instance.
It's from Amir Kubal. By the way, which font are you using? It looks so nice to me. It's Dank Mono font. Used together with Night Owls theme for VS code. Ah, nice. Dank Mono, that's from the guy from Formidable, right? It's a free font. Yeah, nice. No, this is not, unfortunately it's not. Oh, well. Maybe you have to sometimes pay money to use nice stuff. That's weird.
Next question is from Jan. When do you recommend not to use composition? No, as a part of the team that developed composition API, it's very tempting to say just use it everywhere. But in fact, if you, first of all, do not have features to abstract and reuse, and second, if you have a team that already get used to the option API, there is no reason to jump immediately and rewrite everything to composition API. You can evaluate features that need to be reused, and then you can iteratively add them with a composition API. So there's no like a law when to do it. You can always, but it depends on the project, basically, yeah.
Next question is from Ibrahim Beklieff. Which problems does a new composition API solve exactly? If I got it right, it helps to combine logical one thing and place it in one place, like what the React team did when they introduced the React hooks and give opportunity to create custom hooks like useSearch, useSort, et cetera. Yes. You basically get it right. Unfortunately in Vue 2, we lacked a tool to reuse logic, not components. As I mentioned, we could have mixins or scope slot, but still it was a very synthetic thing. And also composition API is very helpful in the case of writing Vue plug-ins for Vue 3. Because currently, if you are author of the library, you would need to work with a Vue instance and extend the Vue prototype. With composition API, it's much easier to do so because you can just simply export functions you created in the plugin and use provide inject within the Vue instance. So basically it's feature reuse and plugin development.
Okay, I hope that gives Ibrahim the complete answer he's looking for. Else he can find you in the Zoom Room.
10. Vue 3 Release and Composition API Advantages
The release candidate for Vue 3 will be out very soon. The composition API in Vue offers advantages similar to React hooks but is custom and not built-in. When deciding which arguments to use as refs or plain values in custom composition functions, consider the need for reactivity.
Else he can find you in the Zoom Room. Next question is from O. Beresford. Is there a guess on when the Vue 3 will be out of beta status? I use Vue 2, and I've been pulling out extra slash non-Vue code via traditional means via SRP for SRP. As you probably understand, I have no allowance to say a certain date, even though we have it in mind. But release candidate is coming very soon, like really very soon. You will be surprised how soon it is. So can I like set an alarm now? Will it make the weekend? Give us a glimpse, Natali. No way, no way. Aw, damn it. Okay, well, good that you're tough on us.
Next question is from Poltermouth30. What advantages does the composition API offer against React hooks? Honestly, it's a bit complex to answer because the question is like, what advantages Vue offers over React, basically? Because they solve similar tasks but different frameworks. Basically, if you work with React for simplicity, you can consider composition API being kind of hooks for Vue. But the only thing is like, someone mentioned custom hooks. Like all composition APIs are custom, we don't have built-in composition APIs. Yeah, okay. So it's apples and oranges. Then closer to each other even.
Okay, another question from Andrew Green H. How do you decide which arguments for your custom composition functions are supposed to be refs and which should be plain values? Basically, if you need reactive value, these should be always ref. You probably noticed that I'm passing options that is static because I didn't plan to change these options in my application. This is just a constant. And this shouldn't be a ref or reactive. If you plan to react on the change of this parameter, this should be always a ref or computed like I did passing a parameter to the sorting option. If we speak about comparison with Vue 2, you can think that non-reactive values if you pass them as non-reactive, is a some function like dollar sign options. If you want something reactive, like from data or computed, they should always be ref or computed.
Okay, I think that's all the time we have for the live Q&A, but I'll just mention once again, if you want to know more about the competition API, please go to the Zoom room. It's in the link. The link is in the timetable below us in the player. There's a timeline below. So there's a new question coming in right now and we're not gonna answer it. So Suwy, will have to go to the Zoom room unfortunately, and we're gonna go to the next speaker. Natalia, thanks a lot for joining us all the way from Ukraine here in Amsterdam, kind of. Thank you. And thanks a lot for being here.