Hey all!
I've got two great new articles for you this week, and some news about the Deja Vue podcast.
First, one on the Options API vs the Composition API.
Last week on Twitter / X there was a lot of discussion going around on whether or not the Options API should be sunset in Vue 4. There were a lot of opinions, of course.
So I spent some time (okay, a lot of time) researching and writing my own take on the issue.
It's a long one, but I think it needs to be in order to tackle this topic properly.
Composition API vs. Options API
Second, I noticed that useAsyncData
in Nuxt can be used both asynchronously and synchronously.
Weird, right?
So I had to dig into it to figure out how that actually works, and how we can use that in our own code.
I wrote all about it on the Mastering Nuxt blog:
Async and Sync? How useAsyncData does it all
Alex and I will be having Evan You on soon, so we're gathering your questions for a Q+A section. So if you have anything you'd like to ask Evan about, just hit reply and we might get to it on podcast!
And after you're done with the tips, don't forget to check out the latest episode of Deja Vue!.
Oh, and I've switched to using vue-email
for the newsletter, so hopefully the formatting is better for you!
— Michael
With the Composition API, we have several great options for watching props.
The recommended approach would be using either watch
or watchEffect
in your script setup
:
import { watch, watchEffect } from "vue";const props = defineProps<{ count: number }>();watch(() => props.count,(val) => {console.log(val);});watchEffect(() => console.log(props.count));
When using the watch
method, we have to provide a getter function instead of passing the value directly. This is because the prop
object itself is reactive, but the individual props are not.
You can test this for yourself by passing in the reactive prop
object directly:
watch(props,(val) => {console.log(val);});
The difference between watch
and watchEffect
is that watch
requires us to specify exactly what we’re watching, while watchEffect
will simply watch every value that is used inside of the method that we pass to it.
So we have a tradeoff between simplicity and flexibility.
If you’re using the setup()
function within the Options API, the only difference is in how we specify the props. Otherwise, everything else works exactly the same:
import { watch, watchEffect } from "vue";export default {props: {count: {type: Number,required: true,},},setup(props) {watch(() => props.count,(val) => {console.log(val);});watchEffect(() => console.log(props.count));},};
The process is straightforward with the Options API.
Just use the name of the prop as the name of the watcher, and you’re good to go!
export default {props: {count: {type: Number,required: true,},},watch: {count(val) {console.log(val);},},};
Although this syntax is simpler than the Composition API syntax, the tradeoff is that there is far less flexibility.
If you want to watch multiple things at once, or have any fine-grained control over the dependencies, the Composition API is much easier to use.
You can optimize the reactivity in your app by using shallowRef
:
const user = shallowRef({name: 'Michael',friends: [{name: 'Travis',friends: [// ...],},{name: 'Matthew',friends: [// ...],},]});
Reactivity is only triggered when the value
of the ref
itself is changed:
// Triggers a reactive updateuser.value = matthew;
But modifying any of the nested properties won’t trigger anything:
// Nothing happensuser.value.name = 'Martin';
Adding deep reactivity to a large object can cost you a lot of performance, so this can be useful for saving some CPU cycles.
You can also manually trigger a reactive update if it’s necessary:
// Log the user whenever it changeswatchEffect(() => console.log(user));// Update nested state (no log happens)user.value.name = 'Martin';// Force a reactive update to triggertriggerRef(user);// [user object]
Here are the docs for shallowRef and triggerRef.
It took me a very long time to realize this, but anything in your component that is reactive can be watched. This includes computed refs as well:
const first = ref('Michael');const last = ref('Thiessen');const fullName = computed(() => `${first.value} ${last.value}`);watchEffect(() => console.log(fullName.value));
Maybe it's just me, but for some reason this wasn't all that intuitive at first for me.
With the Options API it looks like this:
export default {computed: {someComputedProperty() {// Update the computed prop},},watch: {someComputedProperty() {// Do something when the computed prop is updated}}};
You can watch:
In this episode of DejaVue, Michael is joined by Matt Maribojoc, better known as LearnVue on YouTube.
While Alex is being absent at VueConf US, Matt and Michael discuss topics around learning and understanding new programming features - from figuring out what the latest features are over to how to properly learn them and eventually teach them to their audience. Tune into the episode to figure out all of the above, in addition to what level of understanding is "necessary" to teach a certain concepts and why content creation is important for libraries, frameworks and open source in general.
Watch on YouTube or listen on your favourite podcast platform.
Chapters:
In case you missed them:
I wrote this article for VueSchool.io to clear up some misconceptions I've seen around Suspense.
If you load data in your application, I think you'll find it useful.
There are even some code demos so you can code along with the article!
Check it out here: Suspense: Everything You Need to Know
Nuxt 3 provides powerful configuration options, allowing you to adapt your application to different use cases.
The two key parts of Nuxt 3's configuration system are runtimeConfig and appConfig.
This article will explain the purpose and differences between these two options and show you how to use them.
Check it out here: Configuration in Nuxt 3: runtimeConfig vs. appConfig
Here are some upcoming events you might be interested in. Let me know if I've missed any!
The first Czech Vue.js conference, taking place in Cinema City - NovĂ˝ SmĂchov
A community-driven Vue conference in Germany. Listen to great talks from great speakers and meet the wonderful VueJS Community.
My favourite Vue conference, in my own backyard! A three-day event with workshops, speakers from around the world, and socializing.
"If you make a general statement, a programmer says, 'Yes, but...'while a designer says, 'Yes, and...'." — André Bensoussan
The best way to commit something to long-term memory is to periodically review it, gradually increasing the time between reviews 👨‍🔬
Actually remembering these tips is much more useful than just a quick distraction, so here's a tip from a couple weeks ago to jog your memory.
For your unit tests, @nuxt/test-utils
lets you opt-in to a Nuxt environment by adding .nuxt.
to the filename of your test:
./tests/MyComponent.nuxt.test.ts
You can also add a special comment at the top of the file:
@vitest-environment nuxt
Or enable the environment for all Vitest tests in your config:
// vitest.config.tsimport { defineVitestConfig } from '@nuxt/test-utils/config';export default defineVitestConfig({test: {environment: 'nuxt'},};
Michael Hoffman curates a fantastic weekly newsletter with the best Vue and Nuxt links.
p.s. I also have four products/courses: Clean Components Toolkit, Vue Tips Collection 2, Mastering Nuxt 3, and Reusable Components