Day 03 Routing

Vue Router and Navigation Guards

Nested routes, dynamic segments, lazy loading, beforeEach guards, and the navigation patterns that build a multi-page Vue SPA without full page reloads.

~1 hour Intermediate Hands-on Precision AI Academy

Today's Objective

Nested routes, dynamic segments, lazy loading, beforeEach guards, and the navigation patterns that build a multi-page Vue SPA without full page reloads.

01

Why You Need a Store

Imagine a shopping cart. The cart count shows in the navbar. The checkout button shows in the sidebar. The cart items list shows in the main view. All three components need the same data. You could pass it down through props, but that gets unwieldy fast (called 'prop drilling').

A store is a single place where shared state lives. Any component can read from it or write to it directly. Pinia is the official Vue store β€” it's lightweight, TypeScript-friendly, and integrates with Vue DevTools.

02

Creating Your First Pinia Store

Terminal
npm install pinia
src/main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
app.use(createPinia())  // register Pinia with your app
app.mount('#app')
src/stores/cart.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

// defineStore takes an ID (must be unique) and a setup function
export const useCartStore = defineStore('cart', () => {
  // state: reactive variables
  const items = ref([])

  // getters: computed properties
  const totalItems = computed(() =>
    items.value.reduce((sum, item) => sum + item.qty, 0)
  )
  const totalPrice = computed(() =>
    items.value.reduce((sum, item) => sum + item.price * item.qty, 0)
  )

  // actions: functions that modify state
  function addItem(product) {
    const existing = items.value.find(i => i.id === product.id)
    if (existing) {
      existing.qty++
    } else {
      items.value.push({ ...product, qty: 1 })
    }
  }

  function removeItem(productId) {
    items.value = items.value.filter(i => i.id !== productId)
  }

  function clearCart() {
    items.value = []
  }

  // Return everything the component can access
  return { items, totalItems, totalPrice, addItem, removeItem, clearCart }
})
03

Using the Store in Components

CartIcon.vue (reads from store)


ProductCard.vue (writes to store)


πŸ’‘
You can call useCartStore() in multiple components and they all share the exact same instance. Change it in one component and every other component that uses it updates automatically. That's the whole point.
04

Async Actions

Pinia actions can be async β€” just add async to the function. This is where you'd put API calls.

src/stores/users.js
import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useUserStore = defineStore('users', () => {
  const users = ref([])
  const loading = ref(false)
  const error = ref(null)

  async function fetchUsers() {
    loading.value = true
    error.value = null
    try {
      const res = await fetch('https://jsonplaceholder.typicode.com/users')
      users.value = await res.json()
    } catch (e) {
      error.value = 'Failed to load users'
    } finally {
      loading.value = false
    }
  }

  return { users, loading, error, fetchUsers }
})
UserList.vue


πŸ“ Day 3 Exercise
Build a Shopping Cart
  1. Create a Pinia store for a shopping cart with items, add, remove, and clear actions.
  2. Build a ProductList.vue component with 6 hardcoded products and an 'Add to Cart' button on each.
  3. Build a CartSidebar.vue that shows all items in the cart with quantity and price.
  4. Add a cart item count badge to a header/navbar component β€” it should update live as items are added.
  5. Add a 'Total' computed getter to the store and display it in the sidebar.
  6. Add a 'Remove' button per cart item and a 'Clear Cart' button.

Day 3 Summary

What's Next

The foundations from today carry directly into Day 4. In the next session the focus shifts to Pinia State Management β€” building directly on everything covered here.

Day 3 Checkpoint

Before moving on, verify you can answer these without looking:

  • What is the core concept introduced in this lesson, and why does it matter?
  • What are the two or three most common mistakes practitioners make with this topic?
  • Can you explain the key code pattern from this lesson to a colleague in plain language?
  • What would break first if you skipped the safeguards or best practices described here?
  • How does today's topic connect to what comes in Day 4?

Live Bootcamp

Learn this in person β€” 2 days, 5 cities

Thu–Fri sessions in Denver, Los Angeles, New York, Chicago, and Dallas. $1,490 per seat. June–October 2026.

Reserve Your Seat →
Continue To Day 4
Day 4: Vue Router: Multi-Page Apps