DEV Community

Muhammed Erdinç
Muhammed Erdinç

Posted on

Creating Reusable Components with the Composition API & Composables

Image description

Hello, I would like to share with you the article of the presentation on “Creating Reusable Components with the Composition API & Composables” that I explained at Teknasyon Tech 26. Online Meetup. In this article, I wanted to touch on all the topics I explained in the presentation and create a resource for those who like to read more than watch videos. Also, since the presentation is in Turkish, I wanted to explain this subject by writing an article in English.

In this article, we will explore how to write reusable components with the Composition API & Composables that came into our lives with Vue 3, and also why we should use the Composition API and how we can use it correctly.

First of all, let’s look at the problems we encountered while developing with the options API before Vue 3 and why we need Vue 3. Then, let’s try to understand how these problems are solved with Vue 3. At the end of the presentation, we will look at how we can write our composables better.

Don’t Repeat Yourself (DRY)

Image description

One of the most important principles of software development is to avoid repetitive work. Keeping our code reusable and portable is very important. In this way, we can reduce the development cost and produce products faster as a team.

In this article, our aim is to see how to stay away from repetitive tasks in Vue projects and how we can do this more easily with Vue 3.

Single-File Components

Image description

In Vue projects, files with the .vue extension are called Single-File Components(SFC). Vue SFCs allow us to encapsulate template, logic, and styling in a single file. So we can keep Html, Css and JavaScript codes in a single file. In this article, we will focus on the script part and see how we can write our Js code sustainably and how we can organize our business logic.

Before Compisition API

Image description

Before the Composition API, we developed our Vue projects with the Options API. With the Options API, we thought our code was clearer and more understandable. The reason for this is that the code we will write has its own place and we knew what to add where (data, computed, methods etc).

When we look at the sample code block above, we can say that our code looks very organized and easy to read and understand. So is it really so? Although it seems like a good solution for small projects, we can say that this is valid when the developed application is small and simple.

As the application or components grow, things start to get complicated, especially when we start to include more than one logic in a component. Let’s say we hold more than one logic in a component. In this case, since the codes of these logics will always be written in the same blocks, it will be very troublesome to update our code, add or remove a feature. It will be very difficult to understand which method belongs to which logic or which data belongs to which logic at once.

Since we cannot read our code in a certain order, it will be difficult to understand and develop the code. This will appear as a situation that negatively affects the readability of the code.

If we could instead group our code by logic, it would be much easier to read and understand our code. This is exactly where the Composition API comes in.

Image description

In the image above, you can see how complex the code developed with the Options API is compared to the code developed with the Composition API. In the code example below, you can see how a code written with the Options API can be written with the Composition API.

Image description

In summary, the Composition API enables grouping of logics. In this way, we only see the codes related to that logic while performing operations on a logic. Also it will be much easier to separate a logic from a component or add a new logic. For example, when the user logic written with the Composition API in the code above is wanted to be moved to another place, it will be much easier to remove the relevant code from the component since the logic is already grouped.

Avoid Repetitive Work with Options API

As you can imagine, the advantages of the Composition API are not limited to these. There was a topic we mentioned at the beginning of the article. One of the most important principles of software development is to avoid repetitive work. The languages ​​and tools we use provide solutions to help us avoid repetitive work, and these solutions evolve and change throughout the process.

Now, let’s take a look at what solutions we use to avoid repetitive works while developing with the Options API, and why these solutions are insufficient, with examples.

For example, when we want to use a function or code block that we use in a Component throughout the project, let’s look at how we do this with the Options API and what problems we encounter. Next, let’s look at how to solve these problems with the Composition API.

Utility Functions

Image description

The first of these solutions is Utility Functions. In summary, Utility Functions are structures that can take parameters from outside and allow us to encapsulate small code blocks that we expect to return a value as a result. But their use is limited because we cannot define and use vue specific properties (reactive variables, mounted, created etc) inside these functions.

When we examine the image above, you can see that the increment function is defined, but the count reactive variable cannot be defined in the function, so it is defined in the component. Here, utility functions are insufficient when we want to encapsulate the count variable or use other vue-specific properties.

Renderless Components

Image description

Renderless Components is a feature that doesn’t render any html and we can use vue specific properties. When we look at the example in the image above, we see an example of a code that shows the x and y coordinates of the mouse instantly, with a renderless component. Here we can see that we can use vue specific features.

Mixins

Image description

Another method we can use to encapsulate complex code blocks is Mixins. We can say that it was an official way to share code between components, especially when developing with the Options API. Thanks to Mixins, we can encapsulate our business logics and use them in more than one place in our project.

We can learn about the use of mixins by looking at the code example in the image above. Looking at the example, we can see that we can use vue specific features inside mixins.

Although Mixins seem like a very good solution, they can have serious disadvantages. Due to these disadvantages, the use of mixins is not recommended today. Let’s look at these disadvantages together.

One of these disadvantages is that when we use more than one mixin in a component, we cannot understand at first glance which feature comes from which mixin.

Another disadvantage is that there are reactive variables or methods with the same name in different mixins. When we use mixins with the same reactive variables or methods in the same component, conflicts will occur and the code will work incorrectly.

Mixins can be used with Vue 3 but are not recommended. There is now a much better way to encapsulate a code block that contains Vue features. Now let’s examine it together.

Composables

Image description

The most important feature of the Composition API is the Composables. With Composables, we can turn code blocks that contain reactivity into reusable modules. In this way, we can easily use a code in more than one place. However, it is not only for creating global code blocks, but also for separating multiple logic in a component and making the code more readable. Let’s go through the examples and examine the composables.

For example, let’s say we want to write a code that gives the instant coordinate information of the mouse. We have seen how we can do this with renderless components, now we can understand how we can do this with the Composition API by looking at the image below.

Image description

Let’s imagine that we want to use the code developed with the Composition API above in more than one place in the project. The method we can use here is composables.

When we turn the above code into a composable function, our code will be as follows. When we look at the example below, we can see that we can convert our code into a composable function by copy-pasting directly. One of the biggest advantages of the Composition API is that we can easily move our code to another location with almost no changes.

Image description

It is quite simple to use the useMouse composable function that we wrote above in any component. All we have to do is import and start using. In the image below, you can see how easily a composable function can be used.

Image description

Composables vs Mixins

When we look at the examples of Composable functions, we can see that the disadvantages we experience with mixins are not experienced.

  • For example, when we use more than one mixin, it was difficult to understand which feature came from which mixin at first glance, but when we use the refs + destructure model, we can easily understand which feature comes from which Composable.

  • Another disadvantage of Mixins is Namespace collisions. We can avoid namespace collisions by renaming with destructure in Composables.

  • Another advantage is that the values ​​returned from Composable can be passed as arguments to one another, just like regular functions.

We can nest Composables. In this way, we can combine small logics to form larger ones. This is similar to how we use components while developing a web application. When developing a web application, we create larger components by combining small components. In this way, we can develop large web applications without repeating ourselves. We can do the same for our logics. This will allow us to avoid repetitive tasks and save time.

Looking at the example below, we can see how we can nest composables.

Image description

Image description

Looking at the example, we can see that we have created a separate composable for the event listener and can use it in another composable.

Image description

While developing with the Composition API, we mentioned that we can separate our codes according to logics. For example, let’s say we want to write a composable function. The fact that this function we will write has a certain order in itself will increase the readability of the code. When we look at the example above, you can see that the variables are defined as a block in the code and the functions are written as a separate block. Writing Vue-specific (computed, wathers, etc.) features in separate blocks in a certain order will increase the readability of the code. As in the code example at the bottom of the image above, we can separate these blocks with comment lines.

Coding Better Composables

Image description

We looked at code examples related to Composition API and Composables together. We’ve seen that Composables allow us to separate the logic in our code into functions that we can use over and over again. We mentioned that this also makes the code easier to write and read.

Now let’s see how we can write our composables better together. While I was preparing for this subject, there were many sources that I examined, but among these sources, the article “Coding Better Composables” written by Michael Thiessen especially caught my attention. He summarized the subject very well with his way of handling the subject and simple examples. I would definitely recommend checking out the article series. Since this subject is explained very well in the article I mentioned, I would like to explain the subject with the examples there. Since we will proceed in this article without going into too much detail, I recommend that you review the relevant article for detailed information.

While giving information about the subject, we will proceed with code examples again. This time we will use the VueUse library for code examples. VueUse library is an open source library with composables. In this library, we will examine how composables are written. In this way, we will understand what we should pay attention to when writing our own composables.

Options Object Parameter

Image description

Most Composables can have one or more parameters. Instead of passing many parameters to our function, we can pass them all as a single object. We can continue with the object destructure inside the function. It will be advantageous for us to pass parameters other than one or two parameters as objects.

First, we don’t need to know the order of the parameters. Sorting doesn’t matter as long as we pass parameters as objects. In this way, we can prevent possible errors.

Secondly, we can understand what the parameters we pass as objects do from the naming of the properties. This will make our code more readable.

Now let’s look at an example on this subject together. We can see how this is done in the useTitle composable in the VueUse library. The useTitle composable is pretty simple. It allows us to set the title of the page.

Image description

When we look at the example here, other parameters other than the title parameter are taken as options object. We can proceed in this way in the composables we have written.

Flexible Arguments

Image description

We mentioned that Composables can take parameters. These parameters can be primitive javascript types (string, number) as well as reactive variables. In some cases we may want the parameter to be a reactive variable no matter what or a primitive type no matter what. Here, instead of specifically asking for a reactive variable or a primitive type as a parameter, we can accept both and then convert this parameter to the type we need.

When we look at the above example, we can see that this operation can be done very easily with “ref” and “unref”. In this way, regardless of the type of the entered parameter, we can convert it to the type we want (reactive or primitive) and continue. In this way, we can easily avoid possible errors.

Now let’s see how this can be done by going through the UseTitle example.

Image description

When we look at the code above, we can see that whatever parameter is entered, it is made reactive.

Dynamic Return Values

Image description

Composables can return a single value or an object containing multiple values. You can see both examples in the example above. useDark returns a single value, while useMouse returns an object. If we want, we can make the composable’s values ​​dynamic. We can return a single value or object according to the parameter entered from outside. We can do this very easily with a simple control. In the above example, when “controls: true” is entered, the object is returned, otherwise a single value is returned.

This pattern is often a good way to simplify our code. Now let’s see how this is done in the UseNow composable in the VueUse library.

Image description

When we look at the example above, we can see that this operation is done with a simple if check.

Code Organization

Image description

We can use Composables not only to create global code blocks, but also for code organization. For example, as the logics increase in a component, it may become more difficult to read and understand the code. For such cases, we can create a separate composable for each logic and divide our code into small pieces. Also, we can pass a variable from one composable to another composable as a parameter. This will provide a significant advantage for code organization.

Conclusion

Image description

In this article, I first told you about the difficulties we had before the Composition API, with examples. With these examples, we have seen why we need the Composition API and how these problems are overcome with the Composition API. Afterwards, we examined how we can write our Composables better with examples from the article “Coding Better Composables” written by Michael Thiessen.

Hope what is explained will be useful to you :) You can watch my presentation on this topic below (For Turkish readers).

https://youtu.be/bfIDcdHbIbI

Kaynaklar

Top comments (0)