Hello, I've got a brand new article for you. Nuxt Tips Collection is my third book now, and I've learned a lot about how to format books (and PDFs in general). In fact, I built my own tool to make this whole process easier — complete with hot-reloading so I can see the changes I make immediately. I did a big write up all about it and how it works, including the Paged Media module of CSS that you probably haven't ever used: Create Beautiful PDFs with HTML, CSS, and Markdown Of course, don't forget that Nuxt Tips Collection is launching in only a few days on August 5th! You can go here to get a special launch discount on Monday. I've been spending this week editing and polishing the content, making sure it's as good as it can be before I release it next week. I'm also working on a dark mode for the book... Enjoy your summer and your tips! — Michael 🔥 Too Many Props/Options is a Smell Although the total number of options (and required params) isn't itself a problem, it is an indication that the design isn't quite as good as it could be. Chances are that your composable (or component) is trying to do more than one thing, and should instead be separated into several composables. The point of composables is that they each do one specific thing really well, and can be composed together to produce more complex functionality. Imagine that we have a useEvent composable that looks like this: import { ref, onMounted, onBeforeUnmount } from 'vue'; export function useEvent(event, handler, interval, options) => { // Default to targeting the window const { target = window, ...listenerOptions } = options; const startInterval = () => { setInterval(handler, interval); }; onMounted(() => { target.addEventListener(event, startInterval, listenerOptions); }); onBeforeUnmount(() => { target.removeEventListener(event, startInterval, listenerOptions); }); };
We'd use it like this. As soon as the button is clicked, we'll log to the console every second: import useEvent from '~/composables/useEvent.js'; useEvent( 'click', () => console.log('Logging every second'), 1000, { target: buttonElement, } );
We can see that it's doing two separate things: - Listening for events
- Setting up an interval
Instead of including the interval functionality in our useEvent composable, it makes more sense to break it out into a second composable: export function useInterval(callback, options) { const { interval = 1000 } = options; const intervalId = setInterval(callback, interval); return () => clearInterval(intervalId); };
Our useEvent composable becomes simpler: import { onMounted, onBeforeUnmount } from 'vue'; export function useEvent(event, handler, options) { // Default to targeting the window const { target = window, ...listenerOptions } = options; onMounted(() => { target.addEventListener(event, handler, listenerOptions); }); onBeforeUnmount(() => { target.removeEventListener(event, handler, listenerOptions); }); };
And now we can compose the two together to get the desired effect: import useEvent from '~/composables/useEvent.js'; import useInterval from '~/composables/useInterval.js'; useEvent( 'click', () => useInterval( () => console.log('Logging every second') ), { target: buttonElement, } );
When we click on the buttonElement , we call useInterval to set up the interval that will log to the console every second. 🔥 Restrict a prop to a list of types With the Composition API we get fantastic TypeScript support, so this is quite straightforward: defineProps<{ src: string; style: 'square' | 'rounded'; }>();
Doing this in the Options API is more complicated, and not as powerful as TypeScript. Using the validator option in a prop definition you can restrict a prop to a specific set of values: export default { name: 'Image', props: { src: { type: String, }, style: { type: String, validator: s => ['square', 'rounded'].includes(s) } } };
This validator function takes in a prop and returns either true or false — if the prop is valid or not. I often restrict props like this when I need more options than a boolean will allow but still want to restrict what can be set. Button types or alert types (info, success, danger, warning) are some of the most common uses — at least in what I work on. Colours, too, are a really great use case for this. 🔥 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 #</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. 🎙️ #018 — Insights from the Nuxt Team Retreat In this episode of DejaVue, Alex and Michael talk about the previous "IRL Nuxt event", which was a team meeting where most Nuxt Core Team members met in France. Together, they discuss why they met, what happened, why there was a delicious cake and further insights from the retreat, like more breaking changes to Nitro and Nuxt, codemods and other topics. Enjoy the episode! Watch on YouTube or listen on your favourite podcast platform. Chapters: In case you missed them: 📜 Prisma with Nuxt 3: Getting Data with Prisma (4 of 5) We've got our database filled with data — now we need to fetch that data. Prisma gives us a ton of flexibility and power in how we do that. We can easily make complex queries, all while keeping everything typesafe — you just have to know a couple tricks to get it to work correctly. In this fourth article in the series, I'll show you how to get data from your database using Prisma. Check it out here: Prisma with Nuxt 3: Getting Data with Prisma (4 of 5) 📜 Coding Better Composables: Flexible Arguments (2/5) I teamed up with Vue Mastery to create this series on coding better composables. In this series we cover five different patterns. For each, we show how you can implement it and then we see it in action with a composable from VueUse. This second article is on using ref and unref to make the arguments more flexible. Check it out here: Coding Better Composables: Flexible Arguments (2/5) 📅 Upcoming Events Here are some upcoming events you might be interested in. Let me know if I've missed any! PragVue 2024 — (September 17, 2024) The first Czech Vue.js conference, taking place in Cinema City - Nový Smíchov Check it out here Vuejs.de Conf — (October 8, 2024 to October 9, 2024) A community-driven Vue conference in Germany. Listen to great talks from great speakers and meet the wonderful VueJS Community. Check it out here Vue Fes Japan 2024 — (October 19, 2024) Check it out here VueConf Toronto 2024 — (November 18, 2024 to November 20, 2024) My favourite Vue conference, in my own backyard! A three-day event with workshops, speakers from around the world, and socializing. Check it out here 💬 Mass producing software "You can mass-produce hardware; you cannot mass-produce software; you cannot mass-produce the human mind." — Michio Kaku 🧠 Spaced-repetition: The Hidden Component 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. Looking at a component itself is the primary way that we can figure out when and how to refactor it. But we can also look at how the component is used for some clues. Specifically, we're looking to see if there are subsets of this component where those features are only used together. This suggests that there may be more than one component hidden inside of this one. Let's say we have the following component: <template> <div v-if="conditional"> <!-- ... --> </div> <div v-else> <!-- ... --> </div> </template>
Because the v-if is at the root, we know that it's not actually adding any value to this component. Instead, we can simplify by splitting into one component for each branch of our conditional: <template> <ComponentWhereConditionalIsTrue /> <ComponentWhereConditionalIsFalse /> </template>
Now, we don't need to hard-code the conditional prop — we can just use the more descriptive and specific component. For another example, if prop1 and prop2 are only ever used together, but never with prop3 and prop4 , it could mean that the functionality relying on prop1 and prop2 should be separated from the rest of the component. In this illustration, the usage of MyComponent always uses two distinct sets of props, prop1 and prop2 , or prop3 and prop4 : <MyComponent prop-1="someValue" prop-2="anotherValue" /> <MyComponent prop-1="hello" prop-2="world" /> <MyComponent :prop-3="34" prop-4 />
In our theoretical refactoring, we would split the component to work like this: <FirstComponent prop-1="someValue" prop-2="anotherValue" /> <FirstComponent prop-1="hello" prop-2="world" /> <SecondComponent :prop-3="34" prop-4 />
Here are the steps to do this refactoring: - Look for how the component is being used
- Identify any subsets of behaviour — props, events, slots, etc. — that don't overlap
- Simplify using other patterns until it's easy to understand
- Refactor into separate components based on the subsets of behaviour
Learn more about this pattern in the Clean Components Toolkit. 🔗 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 four products/courses: Clean Components Toolkit, Vue Tips Collection 2, Mastering Nuxt 3, and Reusable Components |
评论
发表评论