**Vue3 Power Play: Build a Real-World Task Manager with Composition API, Pinia & Vite**

Vue3 Power Play: Build a Real-World Task Manager with Composition API, Pinia & Vite

Remember that time I spent hours debugging prop drilling in a Vue 2 project? That’s exactly why Vue3’s Composition API felt like a breath of fresh air when I built my first production app with it. Let me walk you through creating a practical task manager while uncovering the real magic of Vue3’s ecosystem.

Detailed Project Setup & Why Composition API Changes Everything

Step 1: Initialize the Project with Vite

First, let’s initialize our project with Vite (because waiting for Webpack to compile is so 2020):

1
2
3
npm create vite@latest task-manager --template vue
cd task-manager
npm install pinia axios

Step 2: Create Your First Composition API Component

Here’s our first composition API example in src/components/TaskList.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script setup>
import { ref, computed } from 'vue'

const tasks = ref([])
const newTask = ref('')

// All related logic stays together - no more Options API separation
const addTask = () => {
if (newTask.value.trim()) {
tasks.value.push({
id: Date.now(),
title: newTask.value,
completed: false
})
newTask.value = ''
}
}

const pendingTasks = computed(() =>
tasks.value.filter(task => !task.completed)
)
</script>

Why this matters: The old Options API forced us to split logic by option types (data, methods, computed), making related code scatter across components. Now we can organize code by feature - all task-related logic stays together, making components easier to maintain as they grow.

Comprehensive State Management with Pinia

Step 3: Setting Up the Pinia Store

During my freelance days, I once debugged a Vuex store for 3 hours just to find a misspelled mutation name. Pinia solves this beautifully. Let’s create our task store:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// stores/task.js
import { defineStore } from 'pinia'

export const useTaskStore = defineStore('task', {
state: () => ({
tasks: JSON.parse(localStorage.getItem('tasks')) || [],
filter: 'all'
}),

actions: {
addTask(title) {
this.tasks.push({
id: Date.now(),
title,
completed: false
})
this.persistTasks()
},

persistTasks() {
localStorage.setItem('tasks', JSON.stringify(this.tasks))
}
},

getters: {
filteredTasks() {
return this.filter === 'all'
? this.tasks
: this.tasks.filter(task =>
this.filter === 'completed' ? task.completed : !task.completed
)
}
}
})

Practical benefits I’ve noticed:

  • No more mutations vs actions confusion
  • TypeScript support works out of the box
  • Stores are modular by design (no namespacing needed)

Real-World Scenario Handling

Case Study 1: Robust Form Validation with Vuelidate

That time when client-side validation failed and bad data hit my API? Never again. Here’s how we validate tasks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { required, minLength } from '@vuelidate/validators'
import useVuelidate from '@vuelidate/core'

const rules = {
newTask: { required, minLength: minLength(3) }
}
const v$ = useVuelidate(rules, { newTask })

// In template:
<template>
<span v-if="v$.newTask.$error">
{{ v$.newTask.$errors[0].$message }}
</span>
</template>

Case Study 2: Secure Route Guards for Authentication

When building the admin dashboard version of this app, I implemented secure route guards:

1
2
3
4
5
6
7
// router.js
router.beforeEach((to) => {
const authStore = useAuthStore()
if (to.meta.requiresAuth && !authStore.isLoggedIn) {
return '/login'
}
})

Case Study 3: Performance Optimization with Lazy Loading

My production app bundle was huge until I implemented component lazy loading:

1
2
3
const TaskEditor = defineAsyncComponent(() =>
import('./components/TaskEditor.vue')
)

Detailed FAQ & Troubleshooting Guide

Q: My reactive objects aren’t updating - what gives?
A: Remember to use ref() for primitives and reactive() for objects. Common gotcha!

Q: How do I migrate from Vuex to Pinia?
A: Start small - convert one module at a time while maintaining both stores temporarily.

Q: Why is my composition function not reactive?
A: Make sure you’re not destructuring reactive objects - that breaks reactivity.

Where To Go From Here

Further learning resources that helped me level up:

The real power comes when you combine these tools in production projects. After building several apps with Vue3’s ecosystem, I can confidently say it reduces boilerplate while making code more maintainable - especially important when working on teams where multiple developers touch the same components.

[up主专用,视频内嵌代码贴在这]