🔥 (#181) Proxy Basics

Hey there!

We've got more tips for you this week, as always.

I'm also working on a free email course, where you'll build up an entire composition API from scratch, one piece at a time.

It's going to be a lot of fun, and I'll send it out to you when it's ready!

— Michael

🔥 Calling a Method from Outside of the Component

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 component  child.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 component        this.$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.vue  import { 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:

  • The Parent component passes true to trigger prop
  • Watch is triggered, and the Child component calls the method
  • The Child component emits an event to tell the Parent component that the method has been triggered successfully
  • The Parent component resets trigger back to false, so we can do this all over again

Ugh.

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 component  child.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.

🔥 Proxy Basics

Proxies are one of the strangest but most interesting parts of Javascript.

It's a fancy wrapper that lets us create lightweight reactivity systems like in Vue, and so much more.

Defining a proxy is simple. We just need to create a handler object, and then use it on an object:

const handler = {    get(target, prop, receiver) {      return 'proxied!';    },  };  const someObj = {    hello: 'world',  };  const proxy = new Proxy(someObj, handler);  console.log(proxy.hello) // proxied!

It lets us intercept property accesses with the get "trap", so we could force any object to use our own logging method:

const handler = {    get(target, prop, receiver) {      return () => {        if (typeof target[prop] !== "function") return;        // Force the method to use our own logging method        const consoleLog = console.log;        console.log = (msg) => {          consoleLog(`[${prop}] ${msg}`);        };        target[prop]();        console.log = consoleLog;      };    },  };  const someObj = {    hello() {      console.log('world');    }  }  const proxy = new Proxy(someObj, handler);  proxy.hello() // [hello] world

We can also intercept when a property is set, prototypes are accessed, and many more things.

You can find a complete list on MDN:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

🔥 Dynamic Slot Names

We can dynamically generate slots at runtime, giving us even more flexibility in how we write our components:

<!-- Child.vue -->  <template>    <div v-for="step in steps" :key="step.id">      <slot :name="step.name" />    </div>  </template>

Each of these slots works like any other named slot. This is how we would provide content to them:

<!-- Parent.vue -->  <template>    <Child :steps="steps">      <!-- Use a v-for on the template to provide content           to every single slot -->      <template v-for="step in steps" v-slot:[step.name]>        <!-- Slot content in here -->      </template>    </Child>  </template>

We pass all of our steps to the Child component so it can generate the slots. Then we use a dynamic directive argument v-slot:[step.name] inside a v-for to provide all of the slot content.

When might you need something like this?

I can imagine one use case for a complex form generated dynamically. Or a wizard with multiple steps, where each step is a unique component.

I'm sure there are more!

🎙️ #023 — TypeScript Wizardry (with Matt Pocock)

In this episode of DejaVue, Alex and Michael meet up with the one and only TypeScript Wizard Matt Pocock. Together, they talk about how he became a full-time educator and what the pros and cons are, then of course discussing everything around TypeScript - from Types vs. Interfaces, any vs. unknown, Matt's ts-reset library, Flappy Bird in TypeScript and more amazing nuggets.

Watch on YouTube or listen on your favourite podcast platform.

Chapters:

In case you missed them:

📜 Build 3D Scenes Declaratively with TresJS Using Vue

Alvaro has done some really impressive work with TresJS, a 3D library for Vue.

In this article he showcases just how easy it is to create 3D scenes in Vue when using TresJS.

Definitely check it out if you're interested in 3D development with Vue!

Check it out here: Build 3D Scenes Declaratively with TresJS Using Vue

📜 How to clean up global event listeners

Markus wrote a great article on the best way to deal with event handlers in your component.It took me awhile to get into the habit of properly dealing with event handlers like this.

I recently was working on a component that had about 7 or 8 global event handlers, so I used this array pattern:

export default {    created() {      // Add directly so it doesn't become reactive      this.eventListeners = [        ['mouseout', this.handleMouseOut],        ['click', this.handleClick],        // ...      ];      for (const [event, handler] of this.eventListeners) {        window.addEventListener(event, handler);      }    },    beforeDestroy() {      for (const [event, handler] of this.eventListeners) {        window.removeEventListener(event, handler);      }    },  };

Arrays are nothing new, but it was a nice way to clean it up.

Check it out here: How to clean up global event listeners

📅 Upcoming Events

Here are some upcoming events you might be interested in. Let me know if I've missed any!

PragVue 2024 — (September 17, 2024)

The first Czech Vue.js conference, taking place in Cinema City - Nový Smíchov

Check it out here

Vuejs.de Conf — (October 8, 2024 to October 9, 2024)

A community-driven Vue conference in Germany. Listen to great talks from great speakers and meet the wonderful VueJS Community.

Check it out here

Vue Fes Japan 2024 — (October 19, 2024)

Check it out here

VueConf Toronto 2024 — (November 18, 2024 to November 20, 2024)

My favourite Vue conference, in my own backyard! A three-day event with workshops, speakers from around the world, and socializing.

Check it out here

Vuejs Amsterdam 2025 — (March 12, 2025 to March 13, 2025)

The biggest Vue conference in the world! A two-day event with workshops, speakers from around the world, and socializing.

Check it out here

💬 Hardly Ever Happens

""That hardly ever happens" is another way of saying "it happens"." — Douglas Crockford

🧠 Spaced-repetition: Looping Over a Range in Vue

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.

The v-for directive allows us to loop over an Array, but it also let's us loop over a range:

<template>    <ul>      <li v-for="n in 5">Item #</li>    </ul>  </template>

This will render out:

  • Item #1
  • Item #2
  • Item #3
  • Item #4
  • Item #5

When we use v-for with a range, it will start at 1 and end on the specified number.

🔗 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