🔥 (238) Powerful Built-In Storage, Hybrid API, and Watching Arrays and Objects

​ ​

Read this on my blog

Hey all, I hope you're having a great week!

I've got a bunch of great tips and articles for you.

Enjoy!

— Michael

Clean Components Toolkit

Are your Vue components getting messy and hard to maintain? Struggling with when to split components or how to organize your code?

The Clean Components Toolkit teaches you battle-tested patterns and principles to write cleaner, more maintainable Vue apps, including:

  • 3.5 + hours of focused video content plus comprehensive written materials
  • Step-by-step refactoring examples showing real-world applications
  • Interactive quizzes to reinforce your learning
  • 20 + practical tools and patterns for component organization
  • Lifetime access to updates and new content

You'll master:

  • Component splitting and combining — when (and when not) to break up components
  • State management across components — especially as complexity grows
  • Logic organization and reuse — using the three core component types
  • Seamless refactoring techniques — transform messy code into clean, maintainable components
"The Clean Components Toolkit's concise, to-the-point lessons made the learning process feel effortless and led to a deeper understanding of the subject matter." — Alex Rodriguez

Master Clean Components Now →

🔥 Nuxt's Powerful Built-In Storage

Nitro, the server that Nuxt uses, comes with a very powerful key-value storage system:

const storage = useStorage();    // Save a value  await storage.setItem('some:key', value);    // Retrieve a value  const item = await storage.getItem('some:key');

It's not a replacement for a robust database, but it's perfect for temporary data or a caching layer.

One great application of this "session storage" is using it during an OAuth flow.

In the first step of the flow, we receive a state and a codeVerifier. In the second step, we receive a code along with the state again, which let's us use the codeVerifier to verify that the code is authentic.

We need to store the codeVerifier in between these steps, but only for a few minutes — perfect for Nitro's storage!

The first step in the /oauth endpoint we store the codeVerifier:

// ~/server/api/oauth    // ...  const storage = useStorage();  const key = `verifier:${state}`;  await storage.setItem(key, codeVerifier);  // ...

Then we retrieve it during the second step in the /callback endpoint:

// ~/server/api/callback    // ...  const storage = useStorage();  const key = `verifier:${state}`;  const codeVerifier = await storage.getItem(key);  // ...

A simple and easy solution, with no need to add a new table to our database and deal with an extra migration.

This just scratches the surface. Learn more about the unstorage package that powers this: https://github.com/unjs/unstorage

🔥 Hybrid API: Composition API + Options API

You don't have to decide between Options API and Composition API, you can use both:

export default {    setup() {      const darkMode = ref(false);      return { darkMode }    },    methods: {      saveDarkMode() {        localStorage.setItem('dark-mode', this.darkMode);      },    }  };

We can also update values from the Options API:

export default {    setup() {      const darkMode = ref(false);      return { darkMode }    },    methods: {      changeTheme(val) {        this.darkMode = val;      }    }  };

Although you can access Composition API from the Options API, it's a one-way street. The Composition API cannot access anything defined through the Options API:

export default {    setup() {      const darkMode = ref(false);        // We can't access the method      this.changeTheme(true);        return { darkMode }    },    methods: {      changeTheme(val) {        this.darkMode = val;      }    }

This can be useful for incremental adoption of the Composition API, because it lets you use reusable composables in your Options API.

But mixing two styles of writing components is likely to cause more headaches than it solves, so please think twice before doing this!

🔥 Watching Arrays and Objects

The trickiest part of using a watcher is that sometimes it doesn't seem to trigger correctly.

Usually, this is because you're trying to watch an Array or an Object but didn't set deep to true:

watch(    colours,    () => {      console.log('The list of colours has changed!');    },    {      deep: true,    }  );

When using the Options API it would look like this:

export default {    name: 'ColourChange',    props: {      colours: {        type: Array,        required: true,      },    },    watch: {      // Use the object syntax instead of just a method      colours: {        // This will let Vue know to look inside the array        deep: true,          // We have to move our method to a handler field        handler()          console.log('The list of colours has changed!');        }      }    }  }

📜 What are Effect Scopes in Vue?

Learn about effect scopes in Vue, how they work, and how to use them to manage your effects and write better Vue components.

Check it out here: What are Effect Scopes in Vue?

📜 Bulletproof Watchers in Vue

Learn how to write bulletproof watchers in Vue, when to use onCleanup and onWatcherCleanup, and how to build reusable cleanup helpers.

Check it out here: Bulletproof Watchers in Vue

💬 Write Programs

"The only way to learn a new programming language is by writing programs in it." — Dennis Ritchie

🧠 Spaced-repetition: Writable Computed Refs

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.

Computed refs are cool and all, but did you know you can create writable computed refs?

const firstName = ref('');  const lastName = ref('');    const fullName = computed({    get: () => `${firstName.value} ${lastName.value}`,    set: (val) => {      const split = val.split(' '); // ['Michael', 'Thiessen']      firstName.value = split[0];   // 'Michael'      lastName.value = split[1];    // 'Thiessen'    }  });    fullName.value = 'Michael Thiessen';  console.log(lastName.value);      // 'Thiessen'

🔗 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 a bunch of products/courses:

Unsubscribe

评论

此博客中的热门博文

Learn to write insanely good composables in Vue

The magic of scoped slots in Vue ✨ (3/4)