🔥 (#135) Nuxt Nation, private properties, and UI states
Hey there!
Nuxt Nation is on today and tomorrow.
Catch the next sessions and catch the previous ones when the recordings come out: https://nuxtnation.com/
I gave my talk on making interactive experiences with Nuxt Content, and luckily my live coding went smoothly.
Enjoy your tips for this week!
— Michael
Vue Tips Collection
Maybe you just want to stay on top of the latest features, remind yourself of interesting things Vue can do, and get daily inspiration.
Vue Tips Collection is a beautiful book of 115 awesome tips, as well as a daily email to get your creative juices flowing.
🔥 Destructuring in a v-for
Did you know that you can destructure in a v-for
?
<li v-for="{ name, id } in users" :key="id" > {{ name }} </li>
It's more widely known that you can grab the index out of the v-for by using a tuple like this:
<li v-for="(movie, index) in [ 'Lion King', 'Frozen', 'The Princess Bride' ]"> {{ index + 1 }} - {{ movie }} </li>
When using an object you can also grab the key:
<li v-for="(value, key) in { name: 'Lion King', released: 2019, director: 'Jon Favreau', }"> {{ key }}: {{ value }} </li>
It's also possible to combine these two methods, grabbing the key as well as the index of the property:
<li v-for="(value, key, index) in { name: 'Lion King', released: 2019, director: 'Jon Favreau', }"> #{{ index + 1 }}. {{ key }}: {{ value }} </li>
🔥 UI states to get right
When building a UI, there are many different states that you need to consider:
- Normal — Sometimes called the "happy path," this is when things are working as expected. For example, in an email client, you'd show some read emails, some unread emails, and maybe a few that are in the "spam" folder.
-
Loading — Your UI has to do something while getting the data, right? A couple tricks:
- Use a computed prop to combine multiple loading states — you don't want spinners all over the page.
- Wait about
200ms
before showing a spinner. If the data loads before that, it feels faster than if you quickly flash the loading spinner on and then off again.
- Error — Things will go wrong, and you need to handle that gracefully. Effectively communicating problems to users to help them get unstuck is very tricky (don't make me guess the password requirements!). Hopefully, you have a good UX designer. Empty — What happens when you have no emails to read, have completed all your tasks, or haven't uploaded any videos yet? A chart showing the "Last 30 Days" of data will probably look weird with no data.
- Partial Data — Often similar to the empty state, but your big table with filtering and sorting also needs to work with only two rows of data. The list of emails shouldn't break with only one email in it.
- Lots of data — Okay, now you have 1294 unread emails. Does your UI break? Maybe that infinite scrolling doesn't make as much sense as when there were only 42 emails.
🔥 Private properties with script setup
You can limit what properties are available when a component is accessed by $ref
:
export default { expose: ['makeItPublic'], data() { return { privateData: 'Keep me a secret!', }; }, computed: { makeItPublic() { return this.privateData.toUpperCase(); }, }, };
With only makeItPublic
exposed, you can't access the privateData
property through a $ref
anymore:
this.$refs.component.privateData // Will always be undefined
If you're using <script setup>
, everything is locked down by default. If you want to expose a value you have to do so explicitly:
<script setup> import { ref, computed } from 'vue'; const privateData = ref('Keep me a secret!'); const makeItPublic = computed( () => privateData.value.toUpperCase() ); // We don't need to import this because it's a compiler macro defineExpose({ makeItPublic }); </script>
Here defineExpose
is a compiler macro, not an actual function, so we don't have to import anything.
You can find more info on this in the docs.
📜 Prisma with Nuxt 3: Setting up Prisma with Supabase (1 of 5)
Trying to manage database schemas alongside your Nuxt app types can be a challenge.
But with Prisma, most of these problems go away.
It handles all of the boilerplate and coordination, so you just write one single schema that's used in your database and in your TypeScript app.
This is the first article in a series dedicated to showing you how to use Prisma in your Nuxt 3 app.
Check it out here: Prisma with Nuxt 3: Setting up Prisma with Supabase (1 of 5)
💬 Write Programs
"The only way to learn a new programming language is by writing programs in it." — Dennis Ritchie
🧠 Spaced-repetition: Nesting slots
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.
As you start creating more abstractions with Vue, you may need to begin nesting your slots:
<!-- Parent.vue --> <template> <Child> <!-- We take the content from the grand-parent slot and render it inside the child's slot --> <slot /> </Child> </template>
This works similarly to how you would catch an error and then re-throw it using a try...catch
block:
try { // Catch the error reallyRiskyOperation(); } (e) { // Then re-throw as something else for the next // layer to catch and handle throw new ThisDidntWorkError('Heh, sorry'); }
Normally when using a slot we just render the content that's provided to us:
<template> <div> <!-- Nothing to see here, just a regular slot --> <slot /> </div> </template>
But if we don't want to render it in this component and instead pass it down again, we render the slot content inside of another slot:
<template> <Child> <!-- This is the same as the previous code example, but instead of a `div` we render into a component. --> <slot /> </Child> </template>
p.s. I also have four products to help you learn Vue: Clean Components Toolkit, Vue Tips Collection, Mastering Nuxt 3 and Reusable Components
评论
发表评论