Hey!
I've got two things to share:
First, it's been three years of these weekly newsletters.
Thank you for reading!
Honestly, I'm surprised I haven't missed a single week in that time — although it's been close a couple times.
Second, today I'm happy to announce that Reusable Components is now available! You can check it out here (there's also a preview of the course).
To celebrate this big update, it will be 35% off for the seven days.
And just like I have for the last 3 years, here are your tips.
— Michael
In Nuxt we can get detailed information on how our page is loading with the useLoadingIndicator
composable:
const {progress,isLoading,} = useLoadingIndicator();console.log(`Loaded ${progress.value}%`); // 34%
It’s used internally by the <NuxtLoadingIndicator>
component, and can be triggered through the page:loading:start
and page:loading:end
hooks (if you’re writing a plugin).
But we have lots of control over how the loading indicator operates:
const {progress,isLoading,start, // Start from 0set, // Overwrite progressfinish, // Finish and cleanupclear // Clean up all timers and reset} = useLoadingIndicator({duration: 1000, // Defaults to 2000throttle: 300, // Defaults to 200});
We’re able to specifically set the duration
, which is needed so we can calculate the progress
as a percentage. The throttle
value controls how quickly the progress
value will update — useful if you have lots of interactions that you want to smooth out.
The difference between finish
and clear
is important. While clear
resets all internal timers, it doesn’t reset any values.
The finish
method is needed for that, and makes for more graceful UX. It sets the progress
to 100
, isLoading
to true
, and then waits half a second (500ms). After that, it will reset all values back to their initial state.
If you need to run a piece of code only once, there’s a Nuxt composable for that (since 3.9):
<script setup>await callOnce(async () => {// This will only be run one time, even with SSR});</script>
Using callOnce
ensures that your code is only executed one time — either on the server during SSR or on the client when the user navigates to a new page.
It also has a key similar to useFetch
or useAsyncData
, to make sure that it can keep track of what’s been executed and what hasn’t:
<script setup>['one', 'two', 'three'].forEach(item => {// Run once for each itemcallOnce(item, async () => {// Do something with the item});});</script>
By default Nuxt will use the file and line number to automatically generate a unique key, but this won’t work in all cases.
SVGs can be reactive components, too.
After all, they're HTML elements just like div
, span
, and button
.
Here's an SVG component that has a prop to change it's fill colour:
<template><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50" :fill="color" /></svg></template>
<script>export default {name: "SVGComponent",props: {color: String,},};</script>
I'm sure you can build some pretty wild things if you dig into different SVG elements and attributes.
Scoped slots and SVGs? Why not...
Here's a demo if you want to see this example in action.
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
"A good programmer is someone who always looks both ways before crossing a one-way street." — Doug Linder
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.
One thing that’s a little tedious with refs is when you need to access a nested property within the template:
<template><div id="app"><p v-for="el in arr">{{ el.value.text }}</p></div></template>
const arr = reactive([]);arr.push(ref({ text: 'hello' }));arr.push(ref({ text: 'world' }));setTimeout(() => (arr[0].value.text = 'nothing'), 1000);
You can’t just rely on auto-unwrapping of refs, you have to explicitly access the .value
and then grab the nested property from there:
ref.value.nestedProperty
In this case, using a reactive
value might be preferable — if the syntax is really bothering you.
p.s. I also have four products/courses: Clean Components Toolkit, Vue Tips Collection 2, Mastering Nuxt 3, and Reusable Components