MST

星途 面试题库

面试题:Vue中Vue Composition API与Pinia结合的复杂状态管理场景

假设在一个电商Vue应用中,需要通过Pinia管理商品列表、购物车等复杂状态,同时使用Vue Composition API实现响应式数据处理和副作用操作。请描述如何设计状态结构、定义相关的actions和getters,以及在组件中如何高效地使用这些状态和方法,并且说明如何处理跨组件状态共享的问题。
32.1万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

1. 设计状态结构

在Pinia中,我们可以为商品列表和购物车分别定义状态。

// store.js
import { defineStore } from 'pinia'

// 商品列表状态
export const useProductStore = defineStore('product', {
  state: () => ({
    products: [] as Product[],
    // 假设Product类型为 { id: number, name: string, price: number }
  })
})

// 购物车状态
export const useCartStore = defineStore('cart', {
  state: () => ({
    cartItems: [] as CartItem[],
    // 假设CartItem类型为 { productId: number, quantity: number }
  })
})

2. 定义Actions和Getters

  • Actions:用于修改状态的方法。
// 商品列表store的actions
export const useProductStore = defineStore('product', {
  state: () => ({
    products: [] as Product[]
  }),
  actions: {
    async fetchProducts() {
      try {
        const response = await fetch('/api/products')
        const data = await response.json()
        this.products = data
      } catch (error) {
        console.error('Error fetching products:', error)
      }
    }
  }
})

// 购物车store的actions
export const useCartStore = defineStore('cart', {
  state: () => ({
    cartItems: [] as CartItem[]
  }),
  actions: {
    addToCart(productId: number) {
      const existingItem = this.cartItems.find(item => item.productId === productId)
      if (existingItem) {
        existingItem.quantity++
      } else {
        this.cartItems.push({ productId, quantity: 1 })
      }
    },
    removeFromCart(productId: number) {
      this.cartItems = this.cartItems.filter(item => item.productId!== productId)
    }
  }
})
  • Getters:用于从状态派生新的数据。
// 购物车store的getters
export const useCartStore = defineStore('cart', {
  state: () => ({
    cartItems: [] as CartItem[]
  }),
  getters: {
    totalPrice: (state) => {
      let total = 0
      const productStore = useProductStore()
      state.cartItems.forEach(item => {
        const product = productStore.products.find(p => p.id === item.productId)
        if (product) {
          total += product.price * item.quantity
        }
      })
      return total
    }
  }
})

3. 在组件中使用状态和方法

使用Vue Composition API,通过setup函数引入Pinia store。

<template>
  <div>
    <button @click="fetchProducts">Fetch Products</button>
    <ul>
      <li v-for="product in productStore.products" :key="product.id">
        {{ product.name }} - ${{ product.price }}
        <button @click="addToCart(product.id)">Add to Cart</button>
      </li>
    </ul>
  </div>
</template>

<script setup lang="ts">
import { useProductStore, useCartStore } from './store'
const productStore = useProductStore()
const cartStore = useCartStore()

const fetchProducts = () => {
  productStore.fetchProducts()
}

const addToCart = (productId: number) => {
  cartStore.addToCart(productId)
}
</script>

4. 处理跨组件状态共享问题

  • 使用Pinia:由于Pinia是一个状态管理库,它本身就支持跨组件状态共享。不同组件只要引入相同的store实例,就可以共享状态。例如,在一个导航栏组件中显示购物车商品数量:
<template>
  <div>Cart Items: {{ cartStore.cartItems.length }}</div>
</template>

<script setup lang="ts">
import { useCartStore } from './store'
const cartStore = useCartStore()
</script>
  • Provide/Inject:如果需要在组件树中更细粒度地共享状态,可以结合Vue的provideinject。但一般在使用Pinia后,这种情况较少使用。例如:
<!-- ParentComponent.vue -->
<template>
  <div>
    <ChildComponent />
  </div>
</template>

<script setup lang="ts">
import { provide } from 'vue'
import { useCartStore } from './store'
const cartStore = useCartStore()
provide('cartStore', cartStore)
</script>

<!-- ChildComponent.vue -->
<template>
  <div>Cart Total: {{ cartStore.totalPrice }}</div>
</template>

<script setup lang="ts">
import { inject } from 'vue'
const cartStore = inject('cartStore')
</script>