您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關Vue全新狀態管理Pinia怎么用的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
Vuex 作為一個老牌 Vue 狀態管理庫,大家都很熟悉了
Pinia 是 Vue.js 團隊成員專門為 Vue 開發的一個全新的狀態管理庫,并且已經被納入官方 github
為什么有 Vuex 了還要再開發一個 Pinia ?
先來一張圖,看下當時對于 Vuex5 的提案,就是下一代 Vuex5 應該是什么樣子的。【相關推薦:vuejs視頻教程】
Pinia 就是完整的符合了他當時 Vuex5 提案所提到的功能點,所以可以說 Pinia 就是 Vuex5 也不為過,因為它的作者就是官方的開發人員,并且已經被官方接管了,只是目前 Vuex 和 Pinia 還是兩個獨立的倉庫,以后可能會合并,也可能獨立發展,只是官方肯定推薦的是 Pinia
因為在 Vue3 中使用 Vuex 的話需要使用 Vuex4,還只能作為一個過渡的選擇,存在很大缺陷,所以在 Componsition API 誕生之后,也就設計了全新的狀態管理 Pinia
Vuex: State
、Gettes
、Mutations
(同步)、Actions
(異步)
Pinia: State
、Gettes
、Actions
(同步異步都支持)
Vuex 當前最新版是 4.x
Vuex4 用于 Vue3
Vuex3 用于 Vue2
Pinia 當前最新版是 2.x
即支持 Vue2 也支持 Vue3
就目前而言 Pinia 比 Vuex 好太多了,解決了 Vuex 的很多問題,所以筆者也非常建議直接使用 Pinia,尤其是 TypeScript 的項目
Pinia 沒有 Mutations
Actions
支持同步和異步
沒有模塊的嵌套結構
Pinia 通過設計提供扁平結構,就是說每個 store 都是互相獨立的,誰也不屬于誰,也就是扁平化了,更好的代碼分割且沒有命名空間。當然你也可以通過在一個模塊中導入另一個模塊來隱式嵌套 store,甚至可以擁有 store 的循環依賴關系
更好的 TypeScript
支持
不需要再創建自定義的復雜包裝器來支持 TypeScript 所有內容都類型化,并且 API 的設計方式也盡可能的使用 TS 類型推斷
不需要注入、導入函數、調用它們,享受自動補全,讓我們開發更加方便
無需手動添加 store,它的模塊默認情況下創建就自動注冊的
Vue2 和 Vue3 都支持
除了初始化安裝和SSR配置之外,兩者使用上的API都是相同的
支持 Vue DevTools
跟蹤 actions, mutations 的時間線
在使用了模塊的組件中就可以觀察到模塊本身
支持 time-travel 更容易調試
在 Vue2 中 Pinia 會使用 Vuex 的所有接口,所以它倆不能一起使用
但是針對 Vue3 的調試工具支持還不夠完美,比如還沒有 time-travel 功能
模塊熱更新
無需重新加載頁面就可以修改模塊
熱更新的時候會保持任何現有狀態
支持使用插件擴展 Pinia 功能
支持服務端渲染
以 Vue3 + TypeScript
為例
安裝
npm install pinia
main.ts
初始化配置
import { createPinia } from 'pinia'createApp(App).use(createPinia()).mount('#app')
在 store 目錄下創建一個 user.ts
為例,我們先定義并導出一個名為 user
的模塊
import { defineStore } from 'pinia' export const userStore = defineStore('user', { state: () => { return { count: 1, arr: [] } }, getters: { ... }, actions: { ... } })
defineStore
接收兩個參數
第一個參數就是模塊的名稱,必須是唯一的,多個模塊不能重名,Pinia 會把所有的模塊都掛載到根容器上
第二個參數是一個對象,里面的選項和 Vuex 差不多
其中 state
用來存儲全局狀態,它必須是箭頭函數,為了在服務端渲染的時候避免交叉請求導致的數據狀態污染所以只能是函數,而必須用箭頭函數則為了更好的 TS 類型推導
getters
就是用來封裝計算屬性,它有緩存的功能
actions
就是用來封裝業務邏輯,修改 state
比如我們要在頁面中訪問 state 里的屬性 count
由于 defineStore
會返回一個函數,所以要先調用拿到數據對象,然后就可以在模板中直接使用了
<template> <div>{{ user_store.count }}</div> </template> <script setup> import { userStore } from '../store' const user_store = userStore() // 解構 // const { count } = userStore() </script>
比如像注釋中的解構出來使用,是完全沒有問題的,只是注意了,這樣拿到的數據不是響應式的,如果要解構還保持響應式就要用到一個方法 storeToRefs()
,示例如下
<template> <div>{{ count }}</div> </template> <script setup> import { storeToRefs } from 'pinia' import { userStore } from '../store' const { count } = storeToRefs(userStore) </script>
原因就是 Pinia 其實是把 state 數據都做了 reactive
處理,和 Vue3 的 reactive 同理,解構出來的也不是響應式,所以需要再做 ref
響應式代理
這個和 Vuex 的 getters 一樣,也有緩存功能。如下在頁面中多次使用,第一次會調用 getters,數據沒有改變的情況下之后會讀取緩存
<template> <div>{{ myCount }}</div> <div>{{ myCount }}</div> <div>{{ myCount }}</div> </template>
注意兩種方法的區別,寫在注釋里了
getters: { // 方法一,接收一個可選參數 state myCount(state){ console.log('調用了') // 頁面中使用了三次,這里只會執行一次,然后緩存起來了 return state.count + 1 }, // 方法二,不傳參數,使用 this // 但是必須指定函數返回值的類型,否則類型推導不出來 myCount(): number{ return this.count + 1 } }
更新 state 里的數據有四種方法,我們先看三種簡單的更新,說明都寫在注釋里了
<template> <div>{{ user_store.count }}</div> <button @click="handleClick">按鈕</button> </template> <script setup> import { userStore } from '../store' const user_store = userStore() const handleClick = () => { // 方法一 user_store.count++ // 方法二,需要修改多個數據,建議用 $patch 批量更新,傳入一個對象 user_store.$patch({ count: user_store.count1++, // arr: user_store.arr.push(1) // 錯誤 arr: [ ...user_store.arr, 1 ] // 可以,但是還得把整個數組都拿出來解構,就沒必要 }) // 使用 $patch 性能更優,因為多個數據更新只會更新一次視圖 // 方法三,還是$patch,傳入函數,第一個參數就是 state user_store.$patch( state => { state.count++ state.arr.push(1) }) } </script>
第四種方法就是當邏輯比較多或者請求的時候,我們就可以封裝到示例中 store/user.ts 里的 actions 里
可以傳參數,也可以通過 this.xx 可以直接獲取到 state 里的數據,需要注意的是不能用箭頭函數定義 actions,不然就會綁定外部的 this 了
actions: { changeState(num: number){ // 不能用箭頭函數 this.count += num } }
調用
const handleClick = () => { user_store.changeState(1) }
打開開發者工具的 Vue Devtools
就會發現 Pinia,而且可以手動修改數據調試,非常方便
示例:
我們先定義示例接口 api/user.ts
// 接口數據類型 export interface userListType{ id: number name: string age: number } // 模擬請求接口返回的數據 const userList = [ { id: 1, name: '張三', age: 18 }, { id: 2, name: '李四', age: 19 }, ] // 封裝模擬異步效果的定時器 async function wait(delay: number){ return new Promise((resolve) => setTimeout(resolve, delay)) } // 接口 export const getUserList = async () => { await wait(100) // 延遲100毫秒返回 return userList }
然后在 store/user.ts 里的 actions 封裝調用接口
import { defineStore } from 'pinia' import { getUserList, userListType } from '../api/user' export const userStore = defineStore('user', { state: () => { return { // 用戶列表 list: [] as userListType // 類型轉換成 userListType } }, actions: { async loadUserList(){ const list = await getUserList() this.list = list } } })
頁面中調用 actions 發起請求
<template> <ul> <li v-for="item in user_store.list"> ... </li> </ul> </template> <script setup> import { userStore } from '../store' const user_store = userStore() user_store.loadUserList() // 加載所有數據 </script>
在一個模塊的 actions 里需要修改另一個模塊的 state 數據
示例:比如在 chat 模塊里修改 user 模塊里某個用戶的名稱
// chat.ts import { defineStore } from 'pinia' import { userStore } from './user' export const chatStore = defineStore('chat', { actions: { someMethod(userItem){ userItem.name = '新的名字' const user_store = userStore() user_store.updateUserName(userItem) } } })
user 模塊里
// user.ts import { defineStore } from 'pinia' export const userStore = defineStore('user', { state: () => { return { list: [] } }, actions: { updateUserName(userItem){ const user = this.list.find(item => item.id === userItem.id) if(user){ user.name = userItem.name } } } })
感謝各位的閱讀!關于“Vue全新狀態管理Pinia怎么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。