🔥 (#128) When should you use v-if?
Hey all!
I'm just putting the final touches on the pre-release of Clean Components.
Yeah, maybe an oxy-moron, since they aren't exactly the "final" final touches, it being a pre-release and all.
Just all the small details I need in order to get it out to you.
It's really exciting for me, because it feels like this is the thing I've been trying to create for five years, it just took me a long time to figure out exactly how to do it.
Clean Components is a toolkit of techniques, principles, and patterns for building great Vue components.
These tools will help you solve some of the most painful problems you face every day as a Vue developer:
- Master the Art of Component Splitting & Combining — knowing when (and when not) to break up components is crucial
- Unlock Secrets to Effortless Component Testing
- Seamlessly Manage State Across Components — especially as your component tree grows in complexity
- Organize & Reuse Logic in Components with Ease — you'll learn the three types of components you need to keep your logic organized
- Learn Effective Folder Structures to Keep Your App Organized — it's not just about camelCase vs kebab-case
The pre-release focuses on tools to solve the first problem — splitting up components.
So look forward to an email in your inbox soon.
It's just around the corner.
(Oh, and happy issue 2^7!)
— Michael
🔥 When should you use v-if?
Instead of using v-if
, it's sometimes more performant to use v-show
instead:
<ComplicatedChart v-show="chartEnabled" />
When v-if
is toggled on and off, it will create and destroy the element completely. Instead, v-show
will create the element and leave it there, hiding it by setting its style to display: none
.
Doing this can be much more efficient if the component you're toggling is expensive to render.
On the flip side, if you don't need that expensive component immediately, use v-if
so that it will skip rendering it and load the page just a bit faster.
🔥 Directly accessing parent components (and why)
Props down, events up. That's how your components should communicate — most of the time.
But in rare cases, that just doesn't work.
If you need direct access to the parent component, you should just use provide
/inject
to pass down the relevant value or method:
import { provide } from 'vue'; const someMethodInTheParent = () => {}; provide('method', someMethodInTheParent)
Then, inject it into the child component:
import { inject } from 'vue'; const method = inject('method'); method();
In Vue 2, you can also use the instance property $parent
:
// Tight coupling like this is usually a bad idea this.$parent.methodOnParentComponent();
This is simpler, but leads to higher coupling and will more easily break your application if you ever refactor.
You can also get direct access to the application root, the very top-most component in the tree, by using $root
. Vue 2 also has $children
, but these were taken out for Vue 3 (please don't use this one).
When would these be useful?
There are a few different scenarios I can think of. Usually, when you want to abstract some behaviour and have it work "magically" behind the scenes.
You don't want to use props and events to connect up a component in those cases. Instead, you use provide
/inject
, $parent
, or $root
, to automatically connect the components and make things happen.
(This is similar to the Compound Component pattern)
But it's hard to come up with an example where this is the best solution. Using provide
/inject
is almost always the better choice.
🔥 Component Seams Framework: How to split up components
Here's a technique for splitting up components:
The code you write forms natural groups. You want to identify these groups and the seams that run between them.
Once you do that, it's easy to extract components — by keeping things in their natural groups as much as possible.
The Component Seams Framework helps you do that in just three steps:
- Find the seams — they can be found in your template by looking for repeated sections and sections that perform different tasks. You can also find them in your props, state, and computed props, by looking for things that are related and are often updated together.
- Stack the seams — take all of the seams you've found, line them up, and you'll start to see where they agree (and where they don't).
- Split along the seams — piece by piece, we'll pull things out and then figure out what to do with its dependencies. Either include the dependency in the new component, or pass it in to the new component somehow (prop, slot, or event).
📜 24 Time-Saving Tips for Nuxt 3
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 3
💬 Programmers and designers
"If you make a general statement, a programmer says, 'Yes, but...'while a designer says, 'Yes, and...'." — André Bensoussan
🧠 Spaced-repetition: Lightweight State Management
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.
We can add computed and methods directly on to a reactive object:
const counter = reactive({ count: 0, increment() { this.count += 1; }, decrement() { this.count -= 1; }, });
This works because this
is set to the object that the method is accessed through, which happens to be the reactive object.
Vue's reactivity system uses Proxies to watch for when a property is accessed and updated. In this case, we have a small overhead from accessing the method as a property on the object, but it doesn't trigger any updates.
If we had a whole series of counters we can reuse this over and over:
const listOfCounters = []; for (const i = 0; i < 10; i++) { const counter = reactive({ id: i, count: 0, increment() { this.count += 1; }, decrement() { this.count -= 1; }, }) listOfCounters.push(counter); }
In our template we can use the counters individually:
<div v-for="counter in listOfCounters" :key="counter.id"> <button @click="counter.decrement()">-</button> {{ counter.count }} <button @click="counter.increment()">+</button> </div>
Instead of making the entire object reactive, we can use ref
to make only our state reactive:
const counter = { count: ref(0), increment() { this.count.value += 1; }, decrement() { this.count.value -= 1; }, };
This saves us a small and likely unnoticeable overhead. But it also feels somewhat better since we're being more thoughtful with our use of reactivity instead of spraying it everywhere.
Here's our example from before, but this time I'm going to add in a factory function to make it more readable:
const createCounter = (i) => ({ id: i, count: ref(0), increment() { this.count.value += 1; }, decrement() { this.count.value -= 1; }, }); const listOfCounters = []; for (const i = 0; i < 10; i++) { listOfCounters.push(createCounter(i)); }
Of course, we can use a factory method with the previous reactive method as well.
p.s. I also have four courses: Vue Tips Collection, Mastering Nuxt 3, Reusable Components and Clean Components
评论
发表评论