In the world of web development, one cannot just learn one tech stack and climb his way to seniority without constantly learning. The concept of technical debt is a serious part of the job. Although one might not emphasise this in the first years of coding, the more experience you get, the easier it is to see that prioritising speedy delivery over perfect code is something that can easily lead to disastrous effects (the cost of future reworking will show up, in one way or another).
So, as cliché as it sounds, gaining experience as a developer is a journey, not a destination. While the first year(s) of learning a new programming language might seem a burden, once you'll develop your skills, you will learn to write your code as neatly as possible. And more than that, you will learn to adapt to changes, which in my opinion, is the key factor for working in the web development industry.
Unless you code in COBOL 😅, your programming language will suffer changes. I’m talking about bug fixes, performance/feature improvements, polishes brought by contributors, and deprecations. So in terms of writing maintainable code, how do I like to think about it?
Write code as if you will need to refactor it in 2 years’ time.
With this in mind, let’s dive into the highly awaited release of Nuxt 3 and see how different Composition API is versus the former Options API used in Nuxt 2 👩💻.
Let's take a look at some of Nuxt 3’s new additions and what makes them different from Nuxt 2:
Next, let’s dissect some of the most notable features in order to get a better understanding of what these new terms mean:
Until Vue 3, we used to have one official way to create a Vue component which was done using Options API. The whole logic was separated into multiple parts like data, methods, computed, and watchers - but now, with Composition API, you can do all those things in a more organised way, making your code much cleaner and easier to manage.
The primary advantage of Composition API is that it enables more efficient logic reuse, and it solves all the drawbacks of mixins; plus, we also get rid of writing code in different sections of the file.
Let’s look at how much code lays in the folder explorer component from Vue CLI's GUI. Composition API looks way more organised since you don’t have to jump around in the file to make sense of where’s what.
In a nutshell, Composition API solves 2 major limitations that Options API had:
Vue composables are functions that use the composition API to implement a reactive and reusable logic. Composables act as an external function that extracts reactive state and functionality to be used across several other components - similar to the Options API mixins.
Another interesting thing about composables is that they can be nested within each other, meaning one composable function can call one or more other composable functions. Therefore, we are able to break down complex logic into smaller units, like how we separate an entire application using components.
The Composition API in Nuxt 3 does not exclude the Options API, and developers can choose to use either or both of these APIs based on their preferences and requirements.
Using the <script setup> tag in a component defines its reactive state, computed properties, and functions using the Composition API syntax, while using the plain <script> tag tells Nuxt you’re going for the Options API. Let’s see a basic example of how both can work together. As you can notice, we define the hello message via a ref() function instead of data() - this is the new way of declaring reactivity in Vue 3, so let’s start by exploring a bit of the new Reactivity API concepts.
While in Vue 2, we used the data() function in order to declare all variables, with Vue 3, we now have two functions for declaring reactive data - ref() and reactive().
The most significant difference between the two is that the ref() function allows us to declare a reactive state for primitives and objects, while reactive() only declares a reactive state for objects. Let’s take a look at the following example code:
The ref() method takes a single value and returns back a mutable and reactive object. To access the value that ref() is tracking, we access the value property of the returned object. Yet when refs are accessed as top-level properties in the template, they are automatically unwrapped, so there is no need to use .value.
Unlike ref(), reactive() can only be initialised with an object. Each property of the object can be a different reactive variable, however. Also, we don't need to use an intermediary property like .value in order to get or change the properties of our reactive object, we can just call the properties of the object directly.
Ok, now one might ask when to choose one over the other.
We'll always use ref() for primitives, of course, but keep in mind that ref() is good for objects that need to be reassigned, like an array. That’s because when you write reactive(), Vue tracks when that array is being mutated yet there's no way to change it for a different array.
A very nice feature which Nuxt 3 brings is that it can now auto-import Vue APIs (ref(), reactive(), etc.) in order to speed up the delivery of developers’ code. So that means the examples above would work without the import statement that I placed under <script setup>.
The great news is that the auto-import also works for components, composables and helper functions by default without the need to explicitly import them! All exported functions and variables in files placed under the components/, composables/ and utils/ folders are globally available to use in any component.
Of course, in case you want to disable auto-imports for any reason, you can set imports.autoImport to false in your nuxt.config.ts.
Now let’s take a brief look at this diagram and explain the skeleton of a Nuxt 3 app:
Source: Krutie Patel on Twitter
In the first part of this article, we listed the major differences that Nuxt 3 brought over Nuxt 2 and had a look over the new folder structure that a website app has. Now that we went through what Composition API looked like and learned the new ways of declaring reactive data, what I recommend is that you have a look at the official Nuxt 3/ Vue 3 documentation and play around with these concepts on StackBlitz (an online IDE which you’ll see in the docs).
The reason why I suggest getting a good grip on these fundamental concepts is that they lay the base for the next important chapter that will come in the second part of the article: State Management.
In “Understanding Nuxt 3 - Part II“, we will learn how ref() and reactive() can provide a way of managing state across components and have a hands-on experience in which we create a Nuxt 3 app from scratch.
Until then, thanks for reading my article and happy coding!
Stay up to date with the tech solutions we build for startups, scale-ups and companies around the world. Read tech trends and news about what we do besides building apps.