Common Mistakes in
(And, more importantly... how to avoid them)

ue.js

Daniel Kelly
Lead Instructor @ Vue School
Full Stack developer (10 + years)
Husband and Father
presentation Icons from fontawesome.com
Why this topic
?
- We're all human and make mistakes
- Simple mistakes can cause big headaches
- Learn from the mistakes of others
- It's a very practical topic
Why this topic?
?
Mistake # 1

index as :key
<li
v-for="(item, index) in items"
:key="index"
>...</li>
What's wrong with this? 🤔

index as :key
<li
v-for="(item, index) in items"
:key="index"
>...</li>
What's wrong with this? 🤔
❌

index as :key
Bug Manifests Under 2 Conditions
- When the elements in the array change order
- When a nested element or component has it's own state
It's tricky!

Let's look at an example!

index as :key
It's not just for loops!
Let's look at an example!
Mistake # 2

Non-reactive value as dep
const cookiesAccepted = computed(()=>
localStorage.getItem("cookiesAccepted")
)
What's wrong with this? 🤔

Non-reactive value as dep
const cookiesAccepted = computed(()=>
localStorage.getItem("cookiesAccepted")
)
What's wrong with this? 🤔

Non-reactive value as dep
const cookiesAccepted = computed(()=>
localStorage.getItem("cookiesAccepted")
) // 0
localStorage.setItem("cookiesAccepted", 1)
cookiesAccepted.value // 0
Changing the value of local storage doesn't update the value of the computed prop.
const accepted = 0;
const cookiesAccepted = computed(()=> accepted)
This is more obvious

Non-reactive value as dep
Often see this with browser API's:
- localStorage
- Date()
- DOM element properties
(like clientWidth, etc) - etc

Non-reactive value as dep
And, of course, usually these hide in more complex computed props
(nothing as obvious as our simple example)
What's the solution?
🤔

Reactive Deps
VueUse
VueUse
handy reactive wrapper around browser APIs
Let's look at an example!
Mistake # 3

Replacing Reactive State
let posts = reactive([
'Post 1',
'Post 2'
]);
function loadMore(){
// fetch more posts, etc
posts = newPosts;
}
What's wrong
with this? 🤔

Replacing Reactive State
let posts = reactive([
'Post 1',
'Post 2'
]);
function loadMore(){
// fetch more posts, etc
posts = newPosts;
}
What's wrong
with this? 🤔
👈 replacing reactive
kills reactivity

Replacing Reactive State



Replacing Reactive State


Let's look at some examples!
Moral of the story:
just use ref() everywhere!
I'm not the only one,
it's the recommendation of the official Vue.js docs


I'm not the only one,
it's the recommendation of the official Vue.js docs


Oh and one more reason to use ref() everywhere
default watcher depth is different between ref() and reactive()
Let's see an example of that
Mistake # 4

Mutating Props
<script setup lang="ts">
defineProps<{
modelValue: string;
}>();
</script>
<template>
<input id="username" v-model="modelValue" />
</template>
What's wrong with this? 🤔

Mutating Props
<script setup lang="ts">
defineProps<{
modelValue: string;
}>();
</script>
<template>
<input id="username" v-model="modelValue" />
</template>
What's wrong with this? 🤔
Mutating a prop
Let's look at some examples!
Common Vue.js Mistakes and How to Avoid Them

🔥 Free
https://vueschool.io/courses/common-vue-js-mistakes-and-how-to-avoid-them
- Omitting the Key Directive on v-for
- Prop Drilling
- Watching Arrays the Wrong Way
- Replacing Reactive State the Wrong Way
- Unintentionally Mutating Props
- Forgetting to Clean Up Your Manual Event Listeners
- Expecting Changes to Non-Reactive Dependencies to Trigger Updates
- Not Considering TypeScript
- Destructuring Reactive Data
- Calling Composables in the Wrong Place
- Using v-html with User Provided Data
- Unnecessary Manual DOM Manipulation
👈
👈
👈
👈

But before I go!
certificates.dev

83% say the exam is moderate to difficult
74% say it actually helped improve their Vue.js skills






Developer Experience
Your Path to a Dynamic and Engaging
certificates.dev


frontendnation.com
60+
Speakers
vue.school/masterclass



Not just crappy multiple choice questions
👉 you gotta code to pass












Grab Some Swag 🤗





danielkelly_io
I'll tweet out the slides and the codebase after this

Thank you 🙏
Go code awesome things!
(with Vue 😉)
Common Mistakes in Vue.js and How to Avoid Them
By Daniel Kelly
Common Mistakes in Vue.js and How to Avoid Them
- 1,513