Vue?項目中的狀態優化一般都會用Pinia替代Vuex,Pinia 是 Vue 生態系統中的一個輕量級狀態管理庫,作為 Vuex 的替代品,它提供了更簡潔的 API 和更好的性能。
模塊化管理:使用 Pinia 時,建議將狀態拆分為多個 store 模塊,以避免單一狀態樹過于龐大和復雜。這不僅有助于維護,還能提升性能。
懶加載 Store:通過 Pinia 的 defineStore 動態創建 store,當某個 store 僅在特定頁面或組件中需要時,可以延遲加載它。這樣可以減少應用的初始加載時間。
State 持久化:如果某些狀態需要在頁面刷新后保持,可以使用 Pinia 的插件功能將狀態持久化到 localStorage 或 sessionStorage,避免不必要的網絡請求或重新計算。
避免不必要的深度響應:Pinia 允許你明確哪些狀態需要響應式,哪些不需要。對于不需要響應式的復雜對象,可以使用 shallowRef 或 shallowReactive 來減少響應式開銷。
1.?安裝 Pinia 與配置
npm install pinia
設置 Pinia:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'const app = createApp(App)// 創建 Pinia 實例
const pinia = createPinia()app.use(pinia)
app.mount('#app')
?2.?創建模塊化 Store
創建兩個 Store 模塊:userStore 和 productStore。其中 userStore 將使用狀態持久化,productStore 將演示懶加載和避免不必要的深度響應。
stores/userStore.js:
// stores/userStore.js
import { defineStore } from 'pinia'
import { ref, computed, watch } from 'vue'export const useUserStore = defineStore('user', () => {// 初始化狀態,如果 localStorage 中有存儲,優先使用存儲的狀態const name = ref(localStorage.getItem('user-name') || 'John Doe')const age = ref(parseInt(localStorage.getItem('user-age')) || 25)const doubleAge = computed(() => age.value * 2)// 監聽狀態變化,并將其保存到 LocalStoragewatch(() => name.value,(newValue) => {localStorage.setItem('user-name', newValue)})watch(() => age.value,(newValue) => {localStorage.setItem('user-age', newValue.toString())})return {name,age,doubleAge,}
})
stores/productStore.js:
// stores/productStore.js
import { defineStore } from 'pinia'
import { shallowRef } from 'vue'export const useProductStore = defineStore('product', () => {// 使用 shallowRef 來避免不必要的深度響應const products = shallowRef([])const addProduct = (product) => {products.value.push(product)}return {products,addProduct,}
})
3. 懶加載 Store
productStore 僅在需要時加載,例如在某個特定組件中。
components/ProductList.vue:
<template><div><h2>Product List</h2><ul><li v-for="product in products" :key="product.id">{{ product.name }}</li></ul><button @click="addNewProduct">Add Product</button></div>
</template><script setup>
import { useProductStore } from '@ stores/productStore'
import { onMounted } from 'vue'// 懶加載 productStore
const productStore = useProductStore()
const products = productStore.productsconst addNewProduct = () => {productStore.addProduct({ id: Date.now(), name: `Product ${products.length + 1}` })
}onMounted(() => {console.log('ProductList component mounted.')
})
</script>
4.?在其他組件中使用 userStore
components/UserProfile.vue:
<template><div><h2>User Profile</h2><p>Name: {{ name }}</p><p>Age: {{ age }}</p><p>Double Age: {{ doubleAge }}</p></div>
</template><script setup>
import { useUserStore } from '@/store/userStore'// 使用 userStore,這個 Store 狀態會被持久化
const userStore = useUserStore()const { name, age, doubleAge } = userStore
</script>
5.?手動實現狀態持久化
我們在 userStore 中通過 localStorage 手動實現了狀態持久化。如果你需要更加通用的狀態持久化插件,可以創建一個簡單的 Pinia 插件。
plugins/persistedState.js:
// plugins/persistedState.js
export function createPersistedStatePlugin(options = {}) {return ({ store }) => {const { key = store.$id } = options// 從 LocalStorage 初始化狀態const fromStorage = localStorage.getItem(key)if (fromStorage) {store.$patch(JSON.parse(fromStorage))}// 訂閱狀態變化,并將其保存到 LocalStoragestore.$subscribe((mutation, state) => {localStorage.setItem(key, JSON.stringify(state))})}
}
注冊插件
import { createPinia } from 'pinia'
import { createPersistedStatePlugin } from './plugins/persistedState'const pinia = createPinia()
pinia.use(createPersistedStatePlugin())const app = createApp(App)
app.use(pinia)
app.mount('#app')