Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
June 17, 2022 06:28 pm GMT

Composition api or Options api?

Clarification

I would like to note that this article is not expressing hate or anything towards Vue.js.
I LOVE Vue and I sponsor the development of it .
I just want to share my opinion, and I would love to hear your thoughts as well .

Options API is not Vue 2

First, I see a lot of people referring to OptA (Options API) as it is Vue 2 and that using it means you also have to use mixins and whatnot. That's not true.
I don't see why we distinguish between OptA (Options API) and CompA (Composition API).
We can write CompA inside OptA, in the setup method:

import { useCounter } from './my-composables'export default {  setup() {    const [count, increment] = useCounter()    return { count, increment }  },  data: () => ({    username: null  })}

In fact, in the Composition API RFC we saw just that. The introduction of a new component option inside OptA called setup.
So Options API is not Vue 2. You can use CompA api using the setup method, which means you can use composables instead of mixins.

Composition api is powerful

The first time I saw CompA I loved it! With it, we have more control about how we define reactivity, we can have reactivity outside of components and sharing code with composables is a great alternative to mixins.

The first time I tried the setup method along with OptA I thought to myself: "What a wonderful world" .

I replaced my mixins with composables, and I saw that CompA is really powerful and that it unlocks a lot of possibilities.
I could even extract and group code together that have the same logic, and I could even compose them together.
Composables look so clean, and they seem so simple compared to mixins.
Most importantly, you don't have to worry about the drawbacks of mixins.

No one complained about the Options API

It's crystal clear that CompA is a great addition to Vue 3. With it, you can dig deeper and manually control reactivity:

<script>import { ref, reactive } from 'vue'export default {  setup() {    const count = ref(0)    const nonReactive = 'I am not reactive'    const person = reactive({      name: 'John'    })    return { count, person }  }}</script>

Whereas with OptA reactivity works automatically:

<script>export default {  data: () => ({    count: 0,    person: {      name: 'John'    }  })}</script>

So for me, it was like:

Create components with Options API and in advanced cases use Composition API to better control reactivity.

But no! OptA syntax is no longer recommended by Vue team even though I never heard anyone complaining about it.

Options api for Todo apps?

Vue docs say:

For primarily low-complexity scenarios use OptA.
For full applications, use CompA.

img.png

What does this mean? Use options api only for TODO apps?

Even though the setup method was introduced as a new component option, the docs recommend using it only if you have an existing OptA codebase. Because for new apps it's not recommended to use it:

Image description

So it's clear! OptA is not recommended and from my experience on reading the docs, it's discouraged.

Be careful!

If you say that you like OptA more, some devs will attack you!
If you say that you don't like script setup syntax, some devs will respond with:

OptA is Legacy! You don't understand coding. You are a junior! Become a better dev just by using CompA.

DX of the Composition API

Alright, since the Vue team & other devs push us to use CompA, we should drop OptA. Right? R i g h t ??
So let's see some CompA magic seen through my eyes.

Why ref and reactive ??

reactive has some limitations:

  1. We can't pass a nested property of a reactive variable to a function.
  2. We can't use destructuring.
const state = reactive({ count: 0 })// the function receives a plain number and// won't be able to track changes to state.countcallSomeFunction(state.count)// count is a plain number that is disconnected// from state.count.let { count } = state// does not affect original statecount++

And thus, Vue provides us ref to avoid the limitations of reactive. Vue docs say that by using ref we can avoid the limitations of reactive and gives us the following snippet:

const obj = {  foo: ref(1),  bar: ref(2)}// the function receives a ref// it needs to access the value via .value but it// will retain the reactivity connectioncallSomeFunction(obj.foo)// still reactiveconst { foo, bar } = obj

So ref comes as a solution. But does it solve the limitations of reactive ? Why not use the same example we had with reactive but by using ref to have a better comparison ?

// const state = reactive({ count: 0 })const state = ref({ count: 0 })// callSomeFunction(state.count)callSomeFunction(state.value)// let { count } = statelet { count } = state.value

Hmm, that doesn't work either. So ref has the same limitations.
If you pull out a property of that object you will get a non-reactive property.

ref is a smart trick by providing an object that has a value property. While you use the ref as is you are good. If you mess with .value though, you might end up with the limitations of reactive.

Usage in the template

You might wonder, how to display a ref variable in the template ? Should I access it via .value ?

The answer is no. Vue automatically "unwraps" the ref variable and displays the .value.

<script setup>import { ref } from 'vue'const count = ref(0)</script><template>  {{ count }}  <button @click="count++">Increase counter</button></template>

Updating the ref variable in the template can be done without using .value, as you can see from the example above where we directly do count++.

Ref unwrapping

So ref gets unwrapped when we use it in the template.
But not always:

  • Automatic unwrapping of ref applies only to top-level properties.
<script setup>  import { ref } from 'vue'  const object = { foo: ref(1) }</script><template>  {{ object.foo }} <!-- does NOT get unwrapped --></template>
  • Automatic unwrapping of ref in reactive objects:
const count = ref(0)const state = reactive({ count })console.log(state.count) // no need for .value
  • No unwrapping in reactive arrays or native collections like Map:
const books = reactive([ref('Vue 3 Guide')])console.log(books[0].value) // need .value hereconst map = reactive(new Map([['count', ref(0)]]))console.log(map.get('count').value) // need .value here

Ref syncing

Say that we have the 2 following variables:

import { ref, reactive } from 'vue'const count = ref(0)const state = reactive({ count })

From the example above, here are some things that maybe don't work as you think they should work.

  • state.count can be accessed and mutated directly. No state.count.value needed.
  • If we update count variable then state.count will be updated too .
  • If we update state.count then count will get updated too .
  • So state.count and count.value are in sync. If we update one, the other will get updated too. But not always . If we re-assign to state.count another ref then the count will not be in sync anymore.

Whaaat ? Calm down, let's explain it.

So what happens, is that a ref inside a reactive object is getting unwrapped so no .value is available on the refs inside that object.
But remember that there is no unwrapping happening inside a reactive Array or a native collection type like Map or Set.

How about the sync part ? Why does that happen? And why does it stop only when assigning another ref ?

That's how it works. That can be powerful but with great power comes great responsibility.

A lot to keep in mind right? And we only touched on the ref and reactive APIs. But there is more:

Image description

So what?

So, with Composition API:

  • We have to decide what to use: ref or reactive? Believe me, there is no answer to that except that "it depends". Personally I mostly use ref.
  • You have to manually define and make sure you don't lose reactivity. As we learned above, ref and reactive limitations can easily lead to reactivity loss
  • You have to always keep in mind the limitations and the behaviors of how reactivity works. (unwrapping, syncing, .value, etc.)
  • Many APIs like toRef, toRefs, unref, isRef, etc.

It's true that CompA is really powerful, but I believe that the points above show us that the DX is not that great compared to OptA.

Conclusion (`)

CompA is extremely powerful and has a lot of features, but it takes time to learn it and it can become difficult to debug especially if you don't use TypeScript.
Personally, I would say that the Development experience of OptA is much better than CompA for creating components.

You don't have to worry about reactivity loss or what apis to choose for reactivity and be careful with the limitations that come with them, but you focus on the component output.

Generally, I would say that using CompA for creating components has the following disadvantages:

  • Unorganized/verbose code.

I know that people show simple snippets where script setup looks cleaner, but the truth is that in real-world apps the code doesn't look that clean:

image.png

  • lots of lines of ungrouped code
  • difficult to visually analyze the code (refs, functions, comments, etc. in one place)
  • In order to make the code clean, devs usually add empty lines and comments (eg lifecycle hooks, watch etc) which is not ideal
  • it is not clean and intuitive and makes it hard to search for specific sections (eg where is a specific method)
  • enforce extraction. When a setup method becomes relatively big, since it has the above downsides, you feel the push to split it into composables. I've experienced that too many composables make it really difficult to debug and follow the flow of the code and also developers don't initially extract everything. Personally, I like building the component first, and then I do refactoring/cleanup code.

My thoughts

In the beginning of using Vue 3, I loved using OptA for creating components and CompA for things like sharing code, stores, etc. I thought that I had to use CompA for creating components only in advanced use cases just like I was using render-functions (only for advanced use cases).

And I believe that if the Vue team would push towards this way of using Vue, things would be much better.
But from what I see, the recommendation is to use script setup and stick with CompA only.
And this is exactly what I did. I switched to using only CompA.

But, sometimes I work on a Vue 2 project for a part-time job and when I use OptA I feel more productive, and I love the facts that I don't have to manually define reactivity and that I can fold/unfold section of the code, and I visually analyze the code better (where is the method, where is the computed, etc.).

Even though now I am confident using CompA, there are still cases where I fall into reactivity loss or forget about reactivity apis behaviors (e.g. unwrapping, syncing, .value, etc.).

Haven't tried script setup with Typescript extensively yet, but I am experimenting with it, and it definitely feels great. I would dare to say that script setup was made to work only with Typescript because without it, development experience is not that great.

Share your thoughts

All in all, CompA is great. OptA was great too.
Even though I loved OptA, I switched to CompA and probably is just a matter of time in order to get convinced that CompA is the way to go "for building full applications".

Or who knows? I might end up using OptA again despite the fact that docs discourage it.

But what do you think?
Please share your thoughts. Let's discuss!

What do you prefer for creating components? Options or Composition API and why?


Original Link: https://dev.to/the_one/composition-api-or-options-api-59gf

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To