日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
我把Vue3項(xiàng)目中的Vuex去除了,改用 Pinia

Pinia

公司主營業(yè)務(wù):成都做網(wǎng)站、網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)建站是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)建站推出衛(wèi)濱免費(fèi)做網(wǎng)站回饋大家。

pinia 的優(yōu)勢

相對(duì)于以前的 vuex,pinia具有以下優(yōu)勢

  • 更簡單的寫法,代碼更清晰簡潔,支持 composition api 和 options api 語法
  • 更完善的 typescript 支持,無需創(chuàng)建自定義復(fù)雜的包裝類型來支持 TypeScript,所有內(nèi)容都是類型化的,并且 API 的設(shè)計(jì)方式盡可能利用 TS 類型推斷
  • 非常輕量,只有1kb的大小

不需要再注入魔法字符串等進(jìn)行調(diào)用

安裝

yarn add pinia
// or
npm install pinia

定義、使用store

創(chuàng)建一個(gè) pinia 并傳遞給 vue 應(yīng)用

import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from './app.vue'

createApp(App).use(createPinia()).mount('#app')

定義store

store的定義是通過 defineStore 這個(gè)函數(shù),

它需要一個(gè)唯一的名稱,該名稱可以作為第一個(gè)參數(shù)傳遞,也可以用 id 熟悉傳遞。

import { defineStore } from 'pinia'
export const useMainStore = defineStore('main', {
// other options...
})

import { defineStore } from 'pinia'
export const useMainStore = defineStore({
id: 'main'
// other options...
})

該 id 是必要的,主要是用于 vue devtools

使用store

import { useMainStore } from '@/stores/main'

export default defineComponent({
setup() {
const store = useMainStore()
return {
store,
}
},
})

上述代碼中,useMainStore實(shí)例化后的,我們就可以在 store 上訪問 state、getters、actions 等(pinia中沒有mutations)。

該 store 是一個(gè) reactive 對(duì)象,所以不需要 “.value”,也不能對(duì)其進(jìn)行解構(gòu)使用,否則失去響應(yīng)性(類似 props)。

storeToRefs

如果一定要對(duì)其進(jìn)行解構(gòu)使用,可以使用 storeToRefs ,類似 vue3 中的 toRefs

import { storeToRefs } from 'pinia'

export default defineComponent({
setup() {
const store = useMainStore()
const { user, company } = storeToRefs(store)
return {
user,
company
}
},
})

state

定義state

在 pinia 中,定義 state 是在函數(shù)中返回 state 初始狀態(tài)

import { defineStore } from 'pinia'

const useMainStore = defineStore('main', {
state: () => ({
teacherName: '艾倫',
userList: [
{ name: '小明', age: 18 },
{ name: '小李', age: 15 },
{ name: '小白', age: 16 },
],
}),
})

export default useMainStore

訪問state

可以通過store 實(shí)例直接訪問

import useMainStore from '@/store/main'

export default defineComponent({
setup() {
const mainStore = useMainStore()
const teacherName = computed(() => mainStore.teacherName)
const userList = computed(() => mainStore.userList)

return {
teacherName,
userList,
}
},
})

也可以直接修改狀態(tài)

import useMainStore from '@/store/main'
export default defineComponent({
setup() {
const mainStore = useMainStore()
function change() {
mainStore.teacherName = '米利'
mainStore.userList.push({
name: '小琪',
age: 19
})
}
return {
change
}
},
})

雖然可以直接修改,但是出于代碼結(jié)構(gòu)來說,全局的狀態(tài)管理還是不要直接在各個(gè)組件處隨意修改狀態(tài),應(yīng)放于 action 中統(tǒng)一方法修改(沒有mutation了)

重置狀態(tài)

可以通過調(diào)用store 上的方法將狀態(tài)重置為初始狀態(tài)

const mainStore = useMainStore()
mainStore.$reset()

$patch

修改state還可以通過使用 $patch 方法

$patch 可以同時(shí)修改多個(gè)值,舉個(gè)例子

import useMainStore from '@/store/main'
export default defineComponent({
setup() {
const mainStore = useMainStore()
mainStore.$patch({
teacherName: '德普',
userList: [
{ name: '小明', age: 18 },
{ name: '小李', age: 15 },
]
})
return {}
},
})

但是,這種寫法的在修改數(shù)組時(shí),例如我只想要把 userList 的中第一項(xiàng)"小明"的age 改為 20,也需要傳入整個(gè)包括所有成員的數(shù)組,這無疑增加了書寫成本和風(fēng)險(xiǎn),于是一般都推薦使用以下的傳入一個(gè)函數(shù)的寫法

mainStore.$patch((state)=>{
state.teacherName = '德普'
state.userList[0].age = 20
})

監(jiān)聽訂閱state

通過 store.$subscribe() 的方法,

該方法的第一個(gè)參數(shù)接受一個(gè)回調(diào)函數(shù),該函數(shù)可以在 state 變化時(shí)觸發(fā)

const subscribe = mainStore.$subscribe((mutation, state) => {
console.log(mutation)
console.log(state)
})

如上所示,該回調(diào)函數(shù)的兩個(gè)參數(shù)

其中 state 是 mainStore 實(shí)例,而 mutation 打印如下

可以發(fā)現(xiàn),打印結(jié)果的mutation對(duì)象主要包含三個(gè)屬性

  • events :是這次state改變的具體數(shù)據(jù),包括改變前的值和改變后的值等等數(shù)據(jù)
  • storeId :是當(dāng)前store的id
  • type:type表示這次變化是通過什么產(chǎn)生的,主要有三個(gè)分別是“direct” :通過 action 變化的”patch object“ :通過 $patch 傳遞對(duì)象的方式改變的“patch function” :通過 $patch 傳遞函數(shù)的方式改變的

停止監(jiān)聽

上面代碼中,調(diào)用mainStore.$subscribe返回的值(即上方示例的 subscribe 變量)可以停止訂閱

subscribe()

store.$subscribe() 的方法的第二個(gè)參數(shù)options對(duì)象,是各種配置參數(shù),包括

  • detached屬性,其值是一個(gè)布爾值,默認(rèn)是 false, 正常情況下,當(dāng) 訂閱所在的組件被卸載時(shí),訂閱將被停止刪除,如果設(shè)置detached值為 true 時(shí),即使所在組件被卸載,訂閱依然可以生效。
  • 其他屬性主要還有 immediate、deep、flush 等等,和 vue3 watch的對(duì)應(yīng)參數(shù)效果一樣。

getter

定義getter

getter 是 store 中的 state 計(jì)算值,以defineStore中的getters屬性定義

getters屬性的值是一個(gè)函數(shù),該函數(shù)的第一個(gè)參數(shù)是 state

const useMainStore = defineStore('main', {
state: () => ({
user: {
name: '小明',
age: 7,
},
}),

getters: {
userInfo: (state) => `${state.user.name}今年${state.user.age}歲了`,
// 這里想要正確推斷參數(shù) state 的類型,則定義 state 時(shí)需要使用箭頭函數(shù)定義
},
})

上面代碼中,getters的值是箭頭函數(shù),當(dāng)getters的值是普通函數(shù)時(shí),可以通過 this 訪問整個(gè)store實(shí)例(如下)

但是如果是普通函數(shù),想要通過 this 獲取state的值并希望this的類型能正確推斷,同時(shí)希望函數(shù)的返回值類型正確推斷,我們需要聲明函數(shù)的返回類型。

getters: {
userDesc: (state) => `${state.user.name}今年${state.user.age}歲了`,
userBesidesDesc(): string{ // 需注明類型
return `${this.user.age}歲的${this.user.name}` // 可以使用 this 獲取值
},
returnUserInfo() {
return this.userDesc // 也可以使用 this 獲取其他getters
},
},

訪問getter

import useMainStore from '@/store/main'
export default defineComponent({
setup() {
const mainStore = useMainStore()

const userDesc = computed(() => mainStore.userDesc)
const userBesidesDesc = computed(() => mainStore.userBesidesDesc)
const returnUserInfo = computed(() => mainStore.returnUserInfo)

return {
userDesc,
userBesidesDesc,
returnUserInfo,
}
},
})

action

定義action

action 是 store 中的 方法,支持同步或異步。

action 定義的函數(shù)可以是普通函數(shù)從而可以通過 this 訪問整個(gè)store實(shí)例,同時(shí)該函數(shù)可以傳入任意參數(shù)并返回任何數(shù)據(jù)

const useMainStore = defineStore('main', {
state: () => ({
count: 0,
}),
actions: {
add() {
this.count++
},
addCountNum(num: number) {
this.count += num
},
},
})

調(diào)用action

setup() {
const mainStore = useMainStore()
function mainAction() {
mainStore.addCount()
}
function addCountTwo() {
mainStore.addCountNum(2)
}
return {
mainAction,
addCountTwo
}
},

監(jiān)聽訂閱action

通過 store.$onAction(),可以監(jiān)聽action的動(dòng)作及結(jié)果等

該函數(shù)可以接收一個(gè)回調(diào)函數(shù)作為參數(shù),回調(diào)函數(shù)的參數(shù)中有五個(gè)屬性,具體如下

const unsubscribe = mainStore.$onAction(({
name, // action 函數(shù)的名稱
store, // store 實(shí)例,這里是 mainStore
args, // action 函數(shù)參數(shù)數(shù)組
after, // 鉤子函數(shù),在action函數(shù)執(zhí)行完成返回或者resolves后執(zhí)行
onError, // 鉤子函數(shù),在action函數(shù)報(bào)錯(cuò)或者rejects后執(zhí)行
}) => {})

舉個(gè)例子,

首先,定義一個(gè)store

import { defineStore } from 'pinia'
const useMainStore = defineStore('main', {
state: () => ({
user: {
name: '小明',
age: 7,
},
}),
actions: {
subscribeAction(name: string, age: number, manualError?: boolean) {
return new Promise((resolve, reject) => {
console.log('subscribeAction函數(shù)執(zhí)行')
if (manualError) {
reject('手動(dòng)報(bào)錯(cuò)')
} else {
this.user.name = name
this.user.age = age
resolve(`${this.user.name}今年${this.user.age}歲了`)
}
})
},
},
})
export default useMainStore

然后在 setup 中使用

import useMainStore from '@/store/main'
import { ref, defineComponent, computed } from 'vue'
export default defineComponent({
setup() {
const mainStore = useMainStore()

function subscribeNormal() {
mainStore.subscribeAction('小李', 18, false)
}

function subscribeError() {
mainStore.subscribeAction('小白', 17, true)
}

const unsubscribe = mainStore.$onAction(({
name, // action 函數(shù)的名稱
store, // store 實(shí)例,這里是 mainStore
args, // action 函數(shù)參數(shù)數(shù)組
after, // 鉤子函數(shù),在action函數(shù)執(zhí)行完成返回或者resolves后執(zhí)行
onError, // 鉤子函數(shù),在action函數(shù)報(bào)錯(cuò)或者rejects后執(zhí)行
}) => {
console.log('action的函數(shù)名', name)
console.log('參數(shù)數(shù)組', args)
console.log('store實(shí)例', store)

after((result) => {
console.log('$onAction after函數(shù)', result)
})

onError(error => {
console.log('錯(cuò)誤捕獲', error)
})
})

return {
subscribeNormal,
subscribeError,
}
},
})

如上,在 setup 中,調(diào)用了 subscribeNormal 函數(shù)后,頁面打印如下

調(diào)用了 subscribeError 函數(shù)后,頁面打印如下

同樣,可以通過調(diào)用 mainStore.$onAction 返回的值來手動(dòng)停止訂閱,在上面代碼的例子中,即是

unsubscribe() // 手動(dòng)停止訂閱

store.$onAction 默認(rèn)在所在組件卸載時(shí)會(huì)被自動(dòng)刪除,可以通過傳遞第二個(gè)參數(shù) true,來將action訂閱和所在組件分開(即組件卸載時(shí),訂閱依然有效)

mainStore.$onAction(callback, true)

store使用位置

在組件中使用時(shí),useStore() 在大多數(shù)情況下都可以在調(diào)用后開箱即用。

在其他地方使用時(shí),需確保在 pinia 激活使用后( app.use(createPinia()) )才能使用 useStore()

例如在路由守衛(wèi)中

import { createRouter } from 'vue-router'
import useMainStore from '@/store/main'
const router = createRouter({
// ...
})

// 報(bào)錯(cuò)
const mainStore = useMainStore()

router.beforeEach((to) => {
// 正常使用
const mainStore = useMainStore()
})

在store中也可以訪問其他store

import { defineStore } from 'pinia'
import { useUserStore } from './user'

export const useMainStore = defineStore('main', {
getters: {
otherGetter(state) {
const userStore = useUserStore()
return userStore.data + state.data
},
},
actions: {
async fetchUserInfo() {
const userStore = useUserStore()
if (userStore.userInfo) {
...
}
},
},
})

pinia插件

pinia store 支持?jǐn)U展,通過 pinia 插件我們可以實(shí)現(xiàn)以下

  • 給 store 添加新屬性
  • 給 store 添加新選項(xiàng)
  • 給 store 添加新方法
  • 包裝已存在的方法
  • 修改甚至刪除actions
  • ...

例如可以寫一個(gè)簡單的插件來給所有store添加一個(gè)靜態(tài)屬性

import { createPinia } from 'pinia'
const pinia = createPinia()
// 傳遞一個(gè)返回函數(shù)
pinia.use(() => ({ env: 'dev' }))
app.use(pinia)

然后,在所有其他的store都可以訪問到上面添加的 env 屬性

setup() {
const mainStore = useMainStore()
console.log(mainStore.env) // dev
}

插件函數(shù)

從上方代碼可以發(fā)現(xiàn),pinia 插件是一個(gè)函數(shù),這個(gè)函數(shù)有一個(gè)可選參數(shù)

import { PiniaPluginContext } from 'pinia'
function myPiniaPlugin(context: PiniaPluginContext) {
console.log(context)
}

context 打印出來主要有

  • app : 當(dāng)前應(yīng)用 Vue.createApp() 創(chuàng)建的 app
  • options : defineStore 配置的數(shù)據(jù)
  • pinia : 當(dāng)前通過 createPinia() 創(chuàng)建的 pinia 實(shí)例
  • store :當(dāng)前 store 實(shí)例

通過 context 我們可以在 store 上設(shè)置屬性

pinia.use(({ store }) => {
store.env = 'dev'
})

這樣,在所有其他的store都可以訪問到上面添加的 env 屬性

pinia 的 store 是通過 reactive 包裝的,可以自動(dòng)解包它包含的任何 ref 對(duì)象

pinia.use(({ store }) => {
store.env = ref('dev')
})

通過上面插件,訪問store 的 env 時(shí)不需要 .value,就可以直接訪問

setup() {
const mainStore = useMainStore()
console.log(mainStore.env) // 不需要加 .value
}

添加外部屬性

當(dāng)需要添加來自其他庫或不需要響應(yīng)式的數(shù)據(jù)時(shí),應(yīng)該用 markRaw() 包裝傳遞的對(duì)象,例如

markRaw 來自 vue3,可以標(biāo)記一個(gè)對(duì)象,使其永遠(yuǎn)不會(huì)轉(zhuǎn)換為 proxy。返回對(duì)象本身。

import { markRaw } from 'vue'
import { router } from './router'
import { axios } from 'axios'

pinia.use(({ store }) => {
store.router = markRaw(router)
store.axios = markRaw(axios)
})

在插件內(nèi)部使用$subscribe、$onAction

pinia.use(({ store }) => {
store.$subscribe(() => {
// react to store changes
})
store.$onAction(() => {
// react to store actions
})
})

新屬性的typescript支持

當(dāng)通過插件添加新屬性時(shí),可以擴(kuò)展 PiniaCustomProperties接口

可以用設(shè)置get,set或者簡單聲明值的類型,以此來安全地寫入和讀取新加的屬性

import 'pinia'

declare module 'pinia' {
export interface PiniaCustomProperties {
set env(value: string | Ref)
get env(): string
// 或者
env: string
}
}

文章標(biāo)題:我把Vue3項(xiàng)目中的Vuex去除了,改用 Pinia
URL網(wǎng)址:http://www.dlmjj.cn/article/djspedo.html