Join 11,067 other Vue devs and get exclusive tips and insights delivered straight to your inbox, every week.
šHey friend! I work hard to send you amazing stuff each week.
āĀ Michael
Hey,
I've got a new article for you, as well as some tips.
The article details how I built my own Twitter scheduler with Markdown support. I explain why I built it, some challenges I ran into, and share the most interesting bits of the project.
Read it here: Building a Twitter Scheduler with Markdown Support.
I'm still working on the next version of Clean Components. There isn't much to share this weekĀ āĀ I'm just wrapping up the planning stage and starting to work on the content.
Enjoy your day, enjoy your week, and enjoy these tips!
āĀ Michael
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.
The <script setup>
sugar in Vue 3 is a really nice feature, but did you know you can use it and a regular <script>
block?
<script setup> // Composition API import { ref } from 'vue'; console.log('Setting up new component instance'); const count = ref(0); </script> <script> // ...and the options API too! export default { name: 'DoubleScript', }; </script>
This works because the <script setup>
block is compiled into the component's setup()
function.
There are a few reasons why you might want to do this:
inheritAttrs
.setup()
is run for every component, if you have code that should only be executed once, you can't include it in <script setup>
. You can put it inside the regular <script>
block, though.<script>
block.Check out the docs for more info
Nuxt 3 comes with 3 different ways to organize your components: pages, layouts, and components.
It can be difficult to know which to use when, so I wrote this article to help explain the differences.
Check it out here: Nuxt 3: Pages vs. Layouts vs. Components
"First, solve the problem. Then, write the code." āĀ John Johnson
I'll be headed to London to give a talk at this conference.
You won't want to miss it!
Get your ticket here: https://vuejslive.com/
This year VueConf US is in New Orleans!
The speaker lineup looks amazing, so make sure to check it out: https://us.vuejs.org/
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.
Nitro, the server that Nuxt 3 uses, comes with a very powerful key-value storage system:
const storage = useStorage(); // Save a value await storage.setItem('some:key', value); // Retrieve a value const item = await storage.getItem('some:key');
Itās not a replacement for a robust database, but itās perfect for temporary data or a caching layer.
One great application of this āsession storageā is using it during an OAuth flow.
In the first step of the flow, we receive a state
and a codeVerifier
. In the second step, we receive a code
along with the state
again, which letās us use the codeVerifier
to verify that the code
is authentic.
We need to store the codeVerifier
in between these steps, but only for a few minutesĀ āĀ perfect for Nitroās storage!
The first step in the /oauth
endpoint we store the codeVerifier
:
// ~/server/api/oauth // ... const storage = useStorage(); const key = `verifier:${state}`; await storage.setItem(key, codeVerifier); // ...
Then we retrieve it during the second step in the /callback
endpoint:
// ~/server/api/callback // ... const storage = useStorage(); const key = `verifier:${state}`; const codeVerifier = await storage.getItem(key); // ...
A simple and easy solution, with no need to add a new table to our database and deal with an extra migration.
This just scratches the surface. Learn more about the unstorage
package that powers this: https://github.com/unjs/unstorage
p.s. I also have four courses: Vue Tips Collection, Mastering Nuxt 3, Reusable Components and Clean Components