Read this on my blog Hey there! I hope you're having a fantastic week. Here are some tips and other Vue content for you. — 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 → 🔥 Configurable Composables We can make our composables more reusable by passing in an object that contains all of the configuration options for how we want the composable to behave: const state = ref({ email: '' }); const { history, undo, redo } = useRefHistory(state, { // Track history recursively deep: true, // Limit how many changes we save capacity: 10, });
We use an object here instead of a long list of parameters: const { history, undo, redo } = useRefHistory(state, true, 10));
Using an options object instead of parameters gives us several benefits. First, it's self-documenting. We have the name of the parameter right beside the value, so we never forget what each value is doing. We can also create a type for the entire options object: export type RefHistoryOptions { deep?: boolean; capacity?: number; }; export type RefHistoryReturn { history: Ref; undo: () => void; redo: () => void; }; export function useRefHistory( ref: Ref, options: RefHistoryOptions ): RefHistoryReturn {};
Second, we don't need to worry about ordering or unused options. The more potential edge cases we cover with a composable, the more options we'll have. But we usually only need to worry about a couple of them at one time — they're all optional. Third, it's much easier to add new options. Because the order doesn't matter and none of the options are required, adding a new capability to our composable won't break anything. We simply add it to the list of possible options and carry on. The pattern doesn't require a lot of work to implement, either: export function useRefHistory(ref, options) { const { deep = false, capacity = Infinity, } = options; // ... };
First, we pass in the options object as the last parameter. This makes it possible to have the options object itself as an optional parameter. The required params come first. Typically, there will only be one or two. More parameters is a code smell, and likely means that your composable is trying to do too much. The required parameter (or parameters) is very often a Ref, or a MaybeRef if we're also implementing the Flexible Arguments Pattern. We then access the options by destructuring. Doing this gives us a really clean and readable way of providing defaults. Remember, these are options so they should all have defaults. If the values are required they should likely have This helps to clarify what options are being used in this composable. It's not uncommon for one composable to use another composable, and in that case some of the options are simply passed along to the inner composable: export function useRefHistory(ref, options) { const { deep = false, capacity = Infinity, ...otherOptions, } = options; // Pass along some options we're not using directly useSomeOtherComposable(otherOptions); };
🔥 Multiple Named Slots Named slots allow you to design components with multiple content insertion points, each identified by a unique name. This is particularly useful when a single slot isn't sufficient for the component's complexity. For example, an Input component might need to display icons before or after the input field: <!-- Input.vue --> <template> <div class="input-styling"> <slot name="icon-before" /> <input ...> <slot name="icon-after" /> </div> </template>
Using the component, you can choose where to place an icon by targeting the specific named slot: <template> <Input> <template #icon-before> <IconBefore /> </template> </Input> <Input> <template #icon-after> <IconAfter /> </template> </Input> </template>
Named slots can be applied in any order and are referenced directly under the component they belong to. They can also be dynamically generated, offering even more flexibility. 🔥 Looping Over a Range in Vue 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 #3</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. 📜 Composition API vs. Options API The Composition API and Options API are two different ways to structure your Vue code. In this article I compare the two in depth, and give my own opinion on which one is best (it's the Composition API). Check it out here: Composition API vs. Options API 📜 24 Time-Saving Tips for Nuxt We know that Nuxt is a fantastic tool. But it has so many amazing features that it's hard to keep track of them all. That's why I've compiled this giant list of 24 Nuxt tips for you — use them to save time and write better Nuxt apps. We cover a lot of topics here, including: - When to use /assets vs. /public directory
- Using runtimeConfig vs. app.config
- Understanding how Universal rendering works (and how it's different from SPA and SSR)
- A utility to make your own NuxtLink components that no one is talking about
- Adding a basic cache to your data fetching — since Nuxt doesn't do this by default
Of course, there is so much more! Check it out here: 24 Time-Saving Tips for Nuxt 💬 Things "Things aren't always #000000 and #FFFFFF." — undefined 🧠 Spaced-repetition: Reusability Fundamentals: The Configuration Pattern 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. So you've got a fantastic CodeBlock component that does syntax highlighting and even shows line numbers: <CodeBlock language="js"> const myMessage = 'Highlighting code is supa ez'; </CodeBlock>
But now, you need to support a second colour theme. Instead of copy and pasting (which is sometimes the right solution!), we can use props to help us create variations: <!-- Uhhh, maybe not the best solution --> <DarkModeCodeBlock language="js"> const myMessage = 'Highlighting code is supa ez'; </DarkModeCodeBlock>
<!-- This is what props were meant for --> <CodeBlock language="js" theme="darkMode" > const myMessage = 'Highlighting code is supa ez'; </CodeBlock>
You already do this intuitively, so this may not be a huge revelation. But the Configuration pattern is a fundamental pattern — you can't ignore it if you want to master reusability. Dealing with prop explosions and understanding the Base Component Pattern is also part of mastering Configuration, the second level of reusability. And the other, more exciting levels of reusability? Well, mastering Configuration is vital to unlocking them. All the other levels build on top of this one. 🔗 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: |
评论
发表评论