Hey all!
In less than a week Mastering Nuxt will be released!
This will be an "early access" at a good discount, with the rest of the lessons following in the weeks to come.
I'll also be doing a live workshop on Nuxt this Friday. You'll get to see how to do a few cool things with Nuxt, and I'll be showing off the demo app you'll build in Mastering Nuxt as well.
If you sign up now you can submit your questions! I'll be answering the most asked questions so make sure to get them in.
Sign up for this free workshop here: https://tally.so/r/w5MLQv?source=michaelthiessen
— Michael
You can call a method from outside of a component by giving it a ref
:
<!-- Parent.vue --><template><ChildComponent ref="child" /></template><script setup>const child = ref(null);// Somewhere in the Parent componentchild.value.method();</script>
If you're using the Options API, your syntax is only slightly different:
<!-- Parent.vue --><template><ChildComponent ref="child" /></template><script>export default {methods: {myMethod() {// This can be anywhere in the Parent componentthis.$refs.child.method();}}}</script>
Let me explain this one a bit more.
Sometimes "best practices" don't work for what you're doing, and you need an escape hatch like this.
Typically, we communicate between components using props and events. Props are sent down into child components, and events are emitted back up to parent components.
<template><ChildComponent:tell-me-what-to-do="someInstructions"@something-happened="hereIWillHelpYouWithThat"/></template>
Occasionally, you may need your parent to trigger a method in the child component. This is where only passing props down doesn't work as well.
You could pass a boolean down and have the child component watch it:
<!-- Parent.vue --><template><ChildComponent :trigger="shouldCallMethod" /></template><script setup>// Child.vueimport { watch } from 'vue';const props = defineProps({trigger: {type: Boolean,required: true}});watch(props.trigger, (newVal) => {if (newVal) {// Call the method when the trigger is set to `true`someMethodInChild();}});</script>
This works fine, but only on the first call. If you needed to trigger this multiple times, you'd have to clean up and reset the state. The logic would then look like this:
true
to trigger
proptrigger
back to false
, so we can do this all over againUgh.
Instead, if we set a ref
on the child component we can call that method directly:
<!-- Parent.vue --><template><ChildComponent ref="child" /></template><script setup>const child = ref(null);// Somewhere in the Parent componentchild.value.method();</script>
Yes, we're breaking the "props down, events up" rule and breaking encapsulation, but it's so much cleaner and easier to understand that it's worth it!
Sometimes the "best" solution ends up being the worst solution.
Here's the best way to think about scoped slots:
Scoped slots are like functions that are passed to a child component that returns HTML.
Once the template is compiled, they are functions that return HTML (technically vnodes
) that the parent passes to the child.
Here's a simple list that uses a scoped slot to customize how we render each item:
<!-- Parent.vue --><template><ScopedSlotList :items="items"><template v-slot="{ item }"><!-- Make it bold, just for fun --><strong>{{ item }}</strong></template></ScopedSlotList></template>
<!-- ScopedSlotList.vue --><template><ul><liv-for="item in items":key="item"><slot :item="item" /></li></ul></template>
We can rewrite this example to use a function instead of a scoped slot:
<!-- Parent.vue --><template><ScopedSlotList:items="items":scoped-slot="(item) => `<strong>${item}</strong>`"></template>
<!-- ScopedSlotList.vue --><template><ul><liv-for="item in items":key="item"v-html="scopedSlot(item)"/></ul></template>
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.
Vite is amazing, I think we can all agree on that statement. But what is Vite actually!? Why is it so great, faster than webpack and the "de-facto standard of the web" already?
Alex is joined by Vite Core Team member Matias Capeletto, better known as Patak, to talk about all these questions.
Learn about the future of Vite, how it uses two bundlers under the hood and why almost every framework adopted it. Enjoy the episode!
Watch on YouTube or listen on your favorite podcast platform.
Chapters:
In case you missed them:
Nuxt offers a set of powerful built-in tools for handling data fetching.
It provides composable functions that make it easy to fetch data and automatically handle server-side rendering, client-side hydration, and error handling. This enables you to write clean and efficient code, ensuring an optimal user experience.
In this article we’ll examine the different methods Nuxt gives us for data fetching.
Check it out here: Data Fetching Basics in Nuxt
Here are some upcoming events you might be interested in. Let me know if I've missed any!
Giving a talk here on component patterns! A great Vue conference, this year held in Tampa. Two days of conference talks, plus a day for workshops.
It's time to get together in Madrid. Join for a full day of talks, activities, and networking with the Vue.js community and ecosystem.
"JavaScript is the only language that I’m aware of that people feel they don’t need to learn before they start using it." — Douglas Crockford
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.
A composable can either return a single value or an object of values. Typically, these values are refs
.
But we can also dynamically switch between the two depending on what we want to use the composable for:
// Grab only the single valueconst now = useNow()// Get more granular access to the composableconst {now,pause,resume} = useNow({ controls: true })
This is great because we may only need a single value most of the time. So why complicate the interface for the main use case?
But by dynamically providing the full object of ref
s, we allow for more advanced use cases as well. Even if they are rarely used.
Here is how we might implement that:
export default useNow(opts) {const {controls = false,} = opts;// Do some things in your composableif (controls) {return { now, pause, resume };} else {return now;}}
Michael Hoffman curates a fantastic weekly newsletter with the best Vue and Nuxt links.
p.s. I also have a bunch of products/courses: