This newsletter was sent out to my list on September 22, 2021. Sign up here to get emails like this each week!
Hi!
First, I need to say a huge THANK YOU to all 212 of you who bought Clean Components in the sale that ended last week.
Your support of my work is absolutely astonishing — it's what gives me the motivation to keep creating.
So, it's officially the first day of fall, at least in the northern hemisphere.
Everything seems to be pumpkin-spiced these days:
- lattes from Starbucks
- scented candles (why)
- Cheerios (okay, I'm willing to try that one)
Please tell me this pumpkin obsession is just a North American thing?
I'll spare you from pumpkin-spiced tips though. These ones are just the regular kind 🎃
— Michael
🔥 Controlled Props — or How to Override Internal State
Here we have a simple Toggle
component that can show or hide content:
<template>
<Toggle title="Toggled Content">
This content can be hidden by clicking on the toggle.
</Toggle>
</template>
It keeps track of its own open
state internally right now.
But what if we want to override that internal state, but only some of the time?
To do this we have to dynamically switch between relying on props and events, and relying on internal state:
export default {
name: 'Toggle',
props: {
title: {
type: String,
required: true,
},
hidden: {
type: Boolean,
// Must be set to `undefined` and not `false`
default: undefined,
}
},
data() {
return {
// Internal state
_hidden: false,
};
},
methods: {
toggleHidden() {
// Switch between emitting an event and toggling state
if (this.hidden !== undefined) {
this.$emit('toggle-hidden');
} else {
this._hidden = !this._hidden;
}
},
},
computed: {
$hidden() {
// Dynamically switch between state or prop
return this.hidden !== undefined
? this.hidden
: this._hidden;
},
},
};
In the Toggle
component we now have to use the $hidden
computed prop:
<template>
<div>
<div
class="title"
@click="toggleHidden"
>
{{ title }}
</div>
<slot v-if="$hidden" />
</div>
</template>
You can check out a more detailed tutorial on my blog.
🔥 Computed Props in Your Template: v-memo
Vue 3.2 gives you fine-grained control over template re-rendering using v-memo
:
<div v-memo="[varA, varB, varC]">
<!-- ... -->
</div>
This works much the same as a computed prop does. An element with v-memo
is only re-rendered when the array changes, but otherwise it caches (or memoizes) the result.
When it's used with v-for
you can selectively re-render only the parts of a list that have changed:
<div
v-for="item in list"
:key="item.id"
v-memo="[item.id === selected]"
>
<!-- ... -->
</div>
Here, we only update the nodes that went selected to unselected, or vice versa. Much faster if you're dealing with extremely long lists!
But since Vue is already so efficient with re-renders, you shouldn't need to use v-memo
very often.
It's definitely a useful tool to help you get more performance — when you really need it.
Check out the docs for v-memo.
🔗 (Sponsored) Come work with me at Vidyard
It's where I've learned all that I know about Vue.
We're rapidly growing our remote engineering team and we need intermediate and senior devs in Canada and the US.
Our stack is Vue + GraphQL + Rails (with React, Node, and some other things, too).
You'll get to work on tons of diverse and interesting projects. Some of the things I've worked on:
- In-house component library — written in Vue, of couse
- Analytics dashboard and pipeline — lots of data, charts, and microservices
- That time we rewrote our entire frontend in Vue — yes, we're very committed to paying down tech debt
- UI for simple video editing
It's also the best place to work (in my opinion):
- In 4 years I've never had to rush to hit a deadline. No evenings, weekends, or stress-induced baldness.
- Every dev has their own "sandbox" — a replica of our production environment, running in AWS, complete with hot reloading.
- The fundamentals: continuous deployment, e2e testing, mentors that help you grow, a focus on doing things right, very few meetings to interrupt your flow, too many memes, never enough memes.
Apply now and get the best job you've ever had.
📜 I didn't know this about computed props
Computed props may not work exactly how you think they do.
That's what a lot of us are finding out after reading Thorsten's post on a common misconception around rendering and computed props.
It's not something you'll run into every day, but it's good to know about if you run into performance problems.
Read it here: When a computed property can be the wrong tool
💬 Working
The greatest performance improvement of all is when a system goes from not-working to working. — John Ousterhout
First, get it to work. Then get it to work well. Don't worry about how good the code is until it's working — that's what refactoring is for.
It's so much easier to transform bad code into good code if it's already working correctly.
🗞 News: Vue.js Amsterdam update
Unfortunately, Vue.js Amsterdam had to cancel their conference for this October due to COVID, but it's on for February 2022!
Here are some upcoming conferences:
- Vue.js Conference (London) — October 20-21 — London and online
- VueConf Toronto — November 22-23 — free + online
- Vuejs Global (Amsterdam) — February 10-11, 2022 — Amsterdam
🧠 Spaced-repetition: Where do you put shared state?
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.
Let's say we have a Button
component that toggles an Accordion
open and closed by changing the variable isOpen
.
But the Button
component changes it's text between "Show" and "Hide" based on the same variable, isOpen
:
// Parent.vue
<template>
<!-- Both components need access to `isOpen` -->
<Button :is-open="isOpen" @click="toggleOpen" />
<Accordion :is-open="isOpen">
Some interesting content in here.
</Accordion>
</template>
These two sibling components (because they are beside each other) need access to the same state, so where do we put it?
Answer: The lowest common ancestor!
Which, in this case, is the parent of both components.
Because state only flows down through props, shared state must be in a common ancestor. And we also want to keep state as close as possible, so we put it in the lowest common ancestor.
While this example may seem obvious to some, when the components sharing state are in separate components, in separate folders, it's harder to see that this is the solution.
Note: we also want to co-locate state with the logic that modifies it, so we have to put the toggleOpen
method in the parent as well.
Exclusive tips and insights every week
Join 8135 other Vue devs and get exclusive tips and insights like these delivered straight to your inbox, every week.
You have great content in your emails. I seriously learn something from every one of them. — Titus Decali
Thanks for another beautiful tip 🙏 — Victor Onuoha
Loving these, and the spaced repetition — Mark Goldstein