🔥 (#168) Design Patterns in Vue

More Vue design patterns for you!

I've added 20% more content to Clean Components Toolkit, and I'm celebrating by giving you a big 35% discount until June 8th! 🎉

It now has a total of 21 patterns on using Vue, which is around 11 hours of content.

I wrote about 12 of them in a new article I just published.

You can check out the course here to see what it's all about. There's also a live preview if you want to sample some of the patterns and tools (you'll have to login with your Github).

Each design pattern comes with:

  • Detailed explanation including tradeoffs and edge cases
  • Step-by-step refactoring example so you can see it in action on real-world code
  • Quiz to test your knowledge
  • A video that goes deeper into each pattern

Get Clean Components Toolkit now!

— Michael

🔥 Force Vue to Re-Render Correctly

If you find yourself needing to force Vue to re-render a component, chances are the reactivity in your app is broken somewhere.

But, if you have a valid use case, forceUpdate is not working, or you simply need to get things working quickly, the best way to do this is through the Key Changing Technique:

<template>    <MyComponent :key="componentKey" />  </template>  <script setup>  import { ref } from 'vue';  const componentKey = ref(0);  const changeKey = () => {    componentKey.value += 1;  };  </script>

Here's how you'd do it with the Options API if you're not using Vue 3 or not using the Composition API:

export default {    data() {      return {        componentKey: 0,      };    },    methods: {      changeKey() {        this.componentKey += 1;      }    }  }

Using the key attribute lets us give Vue more information so it can correctly remove and replace DOM elements on the page. Because of the reactivity system, Vue can get confused about which elements need to be replaced in the DOM and which need to stay.

When we change the value of our key, Vue knows that this is a "new" component. It will destroy the existing component and then create and mount an entirely new one.

Problem solved!

But before you reach for this solution, make sure that there isn't a reactivity issue in your application. This should only be used as a last resort, and is not a recommended approach.

🔥 Understanding scoped slots

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></strong>      </template>    </ScopedSlotList>  </template>
<!-- ScopedSlotList.vue -->  <template>    <ul>      <li        v-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>      <li        v-for="item in items"        :key="item"        v-html="scopedSlot(item)"      />    </ul>  </template>

🔥 Recursive slots

I decided to see if I could make a v-for component using only the template. Along the way, I discovered how to use slots recursively, too.

This is what the component looks like:

<!-- VFor.vue -->  <template>    <div>      <!-- Render the first item -->            <!-- If we have more items, continue!           But leave off the item we just rendered -->      <v-for        v-if="list.length > 1"        :list="list.slice(1)"      />    </div>  </template>

If you wanted to do this with scoped slots — and why wouldn't you?! — it just takes a few tweaks:

<template>    <div>      <!-- Pass the item into the slot to be rendered -->      <slot v-bind:item="list[0]">        <!-- Default -->              </slot>      <v-for        v-if="list.length > 1"        :list="list.slice(1)"      >        <!-- Recursively pass down scoped slot -->        <template v-slot="{ item }">          <slot v-bind:item="item" />        </template>      </v-for>    </div>  </template>

Here is how this component is used:

<template>    <div>      <!-- Regular list -->      <v-for :list="list" />      <!-- List with bolded items -->      <v-for :list="list">        <template v-slot="{ item }">          <strong></strong>        </template>      </v-for>    </div>  </template>

For a more detailed explanation of this example and nested slots, check out my blog post on it:

How to Use Nested Slots in Vue (including scoped slots)

📜 Writing a Cache Composable in Nuxt 3

In this article I explore how to write a composable in Nuxt that can be used to cache data when using fetch.

It's a fun one! We dig into TypeScript, composition API, and Nuxt 3's useFetch composable.

Check it out here: Writing a Cache Composable in Nuxt 3

📜 Building Vue 3 Reactivity from Scratch

In this great article, Lachlan takes us through writing our own ref implementation from scratch.

He gets straight to the point, and the test-driven style makes it easy to understand what we're trying to accomplish.

If you want a deeper understanding of how the composition API works, it's definitely worth a read.

Check it out here: Building Vue 3 Reactivity from Scratch

📅 Upcoming Events

VueConf CN 2024 — July 6, 2024 PragVue 2024 — September 17, 2024 Vuejs.de Conf — October 8, 2024 to October 9, 2024 Vue Fes Japan 2024 — October 19, 2024 VueConf Toronto 2024November 18, 2024 to November 20, 2024

💬 The absence of bugs

"Testing can only prove the presence of bugs, not their absence." — Edsger W. Dijkstra

🧠 Spaced-repetition: What are all these loops for?

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.

I always forget this, so this tip is mostly for me — hopefully, I won't have to keep looking this up!

We have 3 types of for loops in Javascript:

  1. for...in
  2. for...of
  3. for
  4. But how do you know which one to use?

  5. For iterating through properties of an object, use for...in:

const numbers = {    'one': 1,    'two': 2,    'three': 3,  };  // We get the properties of the object, not the values  for (const number in numbers) {    console.log(number);  }  // Prints: 'one' 'two' 'three'

Items in a list (also called an iterable object) like an Array or Set, we use for...of:

const numbers = ['one', 'two', 'three'];  // We get each of the elements in the Array  for (const number of numbers) {    console.log(number);  }  // Prints: 'one' 'two' 'three'

You can use for...in with an Array since all the indices are just the object's properties. But you may not get them in the correct order, and you'll also get any other properties the Array has :/

And you know how to use a regular old for loop, which lets you have a lot more control with some extra typing.

🔗 Want more Vue and Nuxt links?

Michael Hoffman curates a fantastic weekly newsletter with the best Vue and Nuxt links.

Sign up for it here.



p.s. I also have four products/courses: Clean Components Toolkit, Vue Tips Collection 2, Mastering Nuxt 3, and Reusable Components

Unsubscribe

评论

此博客中的热门博文

Scripting News: Tuesday, June 11, 2024

Scripting News: Tuesday, February 13, 2024