Hold on, let's think about it this way
This lesson is about combining everything you learned in the Intermediate/Advanced chapter — component communication, composables, routing, and state management — all at once. The tasks are designed to mirror scenarios you'd actually run into in a real production app. We're not teaching new concepts here; we're testing whether you can combine what you already know. If you finish Task 1 before moving on to Tasks 2 and 3, you'll see how the logic connects more clearly.
Exercises
Task 1: Pass an 'items' array from the parent component down to a child list component as props, and when the delete button in the child is clicked, emit('delete', id) to send the event back to the parent to delete the item. Task 2: Write a composable called useCounter() that returns count, increment, and decrement, then import it into two components at the same time and prove that each component's state stays independent. Task 3: Build a Pinia store called 'useCartStore' with an addItem action and a total price getter, then use Vue Router to navigate between two routes ('/cart' and '/checkout') and verify that the store data doesn't disappear.
Code Example
// useCounter.js (Task 2)
import { ref } from 'vue'
export function useCounter(start = 0) {
const count = ref(start)
const increment = () => count.value++
const decrement = () => count.value--
return { count, increment, decrement }
}
// stores/cart.js (Task 3)
import { defineStore } from 'pinia'
export const useCartStore = defineStore('cart', {
state: () => ({ items: [] }),
getters: {
total: (state) => state.items.reduce((sum, i) => sum + i.price, 0)
},
actions: {
addItem(item) {
this.items.push(item)
}
}
})
// ListItem.vue child (Task 1)
// props: { item: Object }
// emits: ['delete']
// template button: @click="$emit('delete', item.id)"Clicking the delete button in the child removes the item from the parent's items array; the counters in each component using the composable count independently without affecting each other; and even after navigating from the cart page to the checkout page, the cart total price stays intact.Try It in 5 Minutes
Create two components for Task 2 (CounterA.vue, CounterB.vue), import useCounter() into both, and use console.log to prove within 5 minutes that clicking the button in one doesn't affect the other's state.
A Word of Caution
If you want to destructure state from a Pinia store, you must use storeToRefs() — otherwise the reactivity link breaks and the UI stops updating.