🔥 (#146) Mixing local and global styles
Welcome to 2024!
It always takes me awhile to recover from the holidays and get back into work.
But this week I'm finalizing the last details for the launch of Vue Tips Collection 2 — it launches next Tuesday, January 9th.
I've picked up all the hard copies from the printer, because I'm shipping them myself this time. I've never shipped a physical product myself before, so I'm hoping it doesn't end in complete disaster...
FYI — this means there are a limited number of hard copies I can sell.
Here are some details on the second edition of Vue Tips Collection:
- Beautifully designed hardcover book
- 118 tips on how to use Vue more effectively
- 47 completely new tips that aren't in the first edition
- Every single tip re-written, now supporting both the Composition API and the Options API
- PDF emailed to you so you can get to reading while you wait for your physical copy to ship
If you like the tips in this newsletter, you'll love this book.
It's launching next week, January 9th, with a massive discount.
You can find more details here.
As always, enjoy your tips!
— Michael
🔥 Mixing local and global styles together
Normally, when working with styles we want them to be scoped to a single component:
<style scoped> .component { background: green; } </style>
In a pinch though, you can also add a non-scoped style block to add in global styles if you need it:
<style> /* Applied globally */ .component p { margin-bottom: 16px; } </style> <style scoped> /* Scoped to this specific component */ .component { background: green; } </style>
Be careful, though — global styles are dangerous and hard to track down. Sometimes, though, they're the perfect escape hatch and precisely what you need.
🔥 Simpler testing with dependency injection
Jest makes it easy to mock or stub out functions, but you can also use dependency injection to make things easy to stub:
export default { props: { fetchData: { type: Function, required: true, }, }, methods: { setText() { this.text = this.fetchData(); }, }, };
it('should work', () => { const { getByText } = render(MyComponent, { props: { async fetchData() { return 'Test text'; }, }, }); getByText(/Test text/); });
(Example is simplified to illustrate the concept)
This is great for mocking API calls or anything tricky when testing.
If it's coming from outside of the component, it's pretty straightforward to stub it out or mock it how you need to get the test to do what you want.
You can do this in a variety of ways, depending on your use case:
- props
- provide/inject
- Vuex
- custom plugin
(There are probably many more)
🔥 Requiring Injections
Here's a simple composable that lets us require injections in our components:
// useRequiredInjection.js import { inject } from 'vue'; export default useRequiredInjection = (key, fallback) => { const resolved = inject(key, fallback); if (!resolved) { throw new Error(`Could not resolve ${key.description}`); } return resolved; }
Throwing exceptions is fine here. However, because this injection is required, we want to say there is no way this component works without that injection.
This is an effective way to declare that injection intent and makes it easier for your fellow developers to debug missing injections.
Using this composable is also very straightforward:
import useRequiredInjection from './useRequiredInjection'; const userId = useRequiredInjection('userId');
📜 Build a Multi-Step Form in Vue in 5 Minutes
Andrew has put together a great tutorial on how to build a multi-step form in Vue using FormKit.
In only a few minutes you can get a great looking and accessible form up and running!
Check it out here: Build a Multi-Step Form in Vue in 5 Minutes
💬 Theory and Practice
"Theory is when you know something, but it doesn't work. Practice is when something works, but you don't know why. Programmers combine theory and practice: Nothing works and they don't know why." — Unknown
🧠 Spaced-repetition: Creating Magic with Context-Aware Components
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.
Context-aware components are "magical" — they adapt to what's going on around them automatically, handling edge cases, state sharing, and more.
There are 3 main types of context-aware components, but configuration is the one I find most interesting.
1. State Sharing
When you break up a large component into smaller ones, they often still need to share state.
Instead of pushing that work on whoever's consuming the components, you can make this happen "behind the scenes."
To give you more flexibility, you may break up a Dropdown
component into Select
and Option
components. But to make it easier to use, the Select
and Option
components share the selected
state with each other:
<!-- Used as a single component for simplicity --> <Dropdown v-model="selected" :options="[]" /> <!-- Split up for more flexibility --> <Select v-model="selected"> <Option value="mustard">Mustard</Option> <Option value="ketchup">Ketchup</Option> <div class="relish-wrapper"> <Option value="relish">Relish</Option> </div> </Select>
2. Configuration
Sometimes component behaviour needs to change based on what's going on in the rest of the application. This is often done to automagically handle edge cases that would otherwise be annoying to deal with.
A Popup
or Tooltip
should reposition itself so it doesn't overflow out of the page. But if that component is inside a modal, it should move, so it doesn't overflow out of the modal.
This can be done automagically if the Tooltip
knows when it's inside a modal.
3. Styling
You already create context-aware CSS, applying different styles based on what's happening in parent or sibling elements.
.statistic { color: black; font-size: 24px; font-weight: bold; } /* Give some separation between stats that are right beside each other */ .statistic + .statistic { margin-left: 10px; }
CSS variables let us push this further, allowing us to set different values in different parts of the page.
p.s. I also have four products/courses: Clean Components Toolkit, Vue Tips Collection, Mastering Nuxt 3, and Reusable Components
评论
发表评论