阿里云主机折上折
  • 微信号
Current Site:Index > Integration of routing with Pinia

Integration of routing with Pinia

Author:Chuan Chen 阅读数:30768人阅读 分类: Vue.js

Routing and Pinia are two core tools in the Vue.js ecosystem, with the former managing page navigation and the latter handling global state. Combining them can help build more efficient single-page applications.

Basic Routing Configuration

Install vue-router and Pinia in a Vue project:

npm install vue-router pinia

The basic routing file is typically placed in src/router/index.js:

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    component: () => import('../views/AboutView.vue')
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

Pinia Store Creation

Example of a typical Pinia store module:

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
    lastRoute: null
  }),
  actions: {
    increment() {
      this.count++
    },
    setLastRoute(routeName) {
      this.lastRoute = routeName
    }
  }
})

Route Guard Integration

Using Pinia stores in navigation guards:

// router/index.js
import { useCounterStore } from '@/stores/counter'

router.beforeEach((to, from) => {
  const store = useCounterStore()
  store.setLastRoute(from.name)
  
  if (to.meta.requiresAuth && !store.isAuthenticated) {
    return '/login'
  }
})

Accessing Route State in Components

Using both routing and Pinia in components:

<script setup>
import { useRoute } from 'vue-router'
import { useCounterStore } from '@/stores/counter'

const route = useRoute()
const counterStore = useCounterStore()

// Reactively get current route params
const userId = computed(() => route.params.id)

// Modify store state
function incrementWithRoute() {
  counterStore.increment()
  console.log('Current route:', route.fullPath)
}
</script>

<template>
  <div>
    <p>User ID: {{ userId }}</p>
    <button @click="incrementWithRoute">Increment</button>
  </div>
</template>

Dynamic Routing and Store Synchronization

Implementing dynamic route loading based on store state:

// router/index.js
export function setupDynamicRoutes(router, store) {
  store.$onAction(({ name, after }) => {
    if (name === 'loadUserPermissions') {
      after(() => {
        const routes = store.permissions.map(perm => ({
          path: `/${perm}`,
          component: () => import(`@/views/${perm}View.vue`)
        }))
        routes.forEach(route => router.addRoute(route))
      })
    }
  })
}

Route Meta Information and Stores

Enhancing state management with route meta information:

const routes = [
  {
    path: '/admin',
    meta: {
      requiresStore: 'admin',
      storeAction: 'fetchAdminData'
    }
  }
]

router.beforeEach(async (to) => {
  if (to.meta.requiresStore) {
    const store = useStore()
    await store[to.meta.storeAction]()
  }
})

Server-Side Rendering Considerations

Key points to note in SSR environments:

// In entry-server.js
export default async function (context) {
  const pinia = createPinia()
  const app = createApp(App)
  
  app.use(pinia)
  const router = createRouter()
  
  // Sync server-side state
  if (context.piniaState) {
    pinia.state.value = context.piniaState
  }

  await router.push(context.url)
  await router.isReady()
  
  return { app, router, pinia }
}

Testing Strategies

Practical patterns for writing tests:

import { setActivePinia, createPinia } from 'pinia'
import { createRouter, createWebHistory } from 'vue-router'
import { mount } from '@vue/test-utils'

test('uses pinia store with router', async () => {
  setActivePinia(createPinia())
  const router = createRouter({
    history: createWebHistory(),
    routes: []
  })
  
  const wrapper = mount(Component, {
    global: {
      plugins: [router]
    }
  })
  
  await router.push('/test-route')
  expect(wrapper.vm.$route.path).toBe('/test-route')
})

Performance Optimization Tips

Reducing unnecessary state loading:

router.beforeEach((to) => {
  if (to.meta.shouldPrefetch) {
    const store = useStore()
    // Only load if data doesn't exist
    if (!store.isDataLoaded) {
      store.loadInitialData()
    }
  }
})

Type-Safe Integration

Enhancing type checking with TypeScript:

// types/router.d.ts
import 'vue-router'

declare module 'vue-router' {
  interface RouteMeta {
    requiresStore?: string
    storeAction?: keyof typeof useStore
  }
}

// stores/index.ts
export const useStore = defineStore('main', {
  actions: {
    fetchAdminData(): Promise<void> {
      // Implementation logic
    }
  }
})

Error Handling Patterns

Unified navigation error handling:

router.onError((error) => {
  const store = useErrorStore()
  store.logNavigationError(error)
  
  if (isCriticalError(error)) {
    router.push('/system-error')
  }
})

Route Lazy Loading Optimization

Smart preloading with Pinia:

// Track route loading state in the store
const useRouteStore = defineStore('routes', {
  state: () => ({
    loadedRoutes: new Set()
  }),
  actions: {
    markRouteLoaded(routeName) {
      this.loadedRoutes.add(routeName)
    }
  }
})

// Wrap lazy-loaded components
function smartImport(routeName) {
  const routeStore = useRouteStore()
  return {
    component: import(`@/views/${routeName}.vue`),
    loadingComponent: routeStore.loadedRoutes.has(routeName) 
      ? null 
      : LoadingSpinner
  }
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.