開始嘗試做自己的狀態(tài)管理缔逛。
上文說了页响,我們可以定義一個 reactive 結(jié)構(gòu)的userOnline 闺魏,然后注入到根組件里面矾柜,那么相關(guān)的處理函數(shù)要怎么辦呢阱驾?
我么可以寫一個單獨(dú)的js文件,然后用import的方式引入進(jìn)來怪蔑,然后我們就可以做統(tǒng)一的處理了里覆。
js文件如下:
import { provide, inject, reactive, readonly } from 'vue'
import sysUserInfo from './symbol'
const userState = () => {
// 定義標(biāo)識
// const sysUserInfo = Symbol('userOnlineInfo')
// 存放當(dāng)前登錄的用戶信息
const userInfo = reactive({
isLogon: false,
isOnline: false,
userId: 1,
userCode: 'jyk',
userNike: '海洋',
departmentId: 123,
departmentName: '',
role: [1],
power: [1, 2, 3]
})
// 在當(dāng)前組件里面注入
const register = () => {
provide(sysUserInfo, userInfo)
}
// 獲取共享的用戶狀態(tài)
const _user = inject(sysUserInfo)
// 設(shè)置登錄用戶的信息
const setUser = (user) => {
Object.assign(_user, user)
}
// 返回注入的狀態(tài),只讀形式
const getUser = () => {
return readonly(_user)
}
// 返回當(dāng)前用戶是否登錄
const isLogon = () => {
return _user.isLogon
}
return {
// 返回組件內(nèi)狀態(tài)
userInfo: readonly(userInfo),
// 在組件里注入狀態(tài)缆瓣,可以實現(xiàn)子組件共享
register,
// 修改狀態(tài)的函數(shù)
setUser,
// 獲取共享的狀態(tài)
getUser,
// 返回是否登錄的狀態(tài)
isLogon
}
}
export default userState
定義一個 reactive的 userInfo喧枷,實現(xiàn)響應(yīng)式
在函數(shù)內(nèi)部定義 userInfo,然后在return的時候加上readonly作為限制,這樣可以就以避免誤操作而導(dǎo)致直接改變狀態(tài)隧甚。
這里獲取狀態(tài)有兩種方式车荔,一個是在注入的組件的獲取方式,一個是在子組件獲取的方式戚扳。
因為在注入的組件似乎不能用 inject 來獲取忧便,所以只好直接返回 userInfo。于是就出現(xiàn)了兩種獲取狀態(tài)的方式帽借。
使用的時候不要弄混珠增。
如果可以保證在注入的組件里面不會用到狀態(tài)的話,可以把直接返回狀態(tài)的給去掉砍艾,這樣就不會混淆了蒂教。
使用 register 方式注入
引入js文件并不會自動注入,而是需要顯性使用 register 來注入脆荷。
這樣可以明確注入的組件凝垛,另外也可以避免每個組件都注入一個。
如果不使用 register 的話蜓谋,那么就是完全的本組件使用梦皮。
getUser
獲取狀態(tài)的時候,一個要注意使用 inject 桃焕,這樣獲取的才是共享的狀態(tài)届氢,否則就是本組件內(nèi)部的單獨(dú)的狀態(tài)了。
另外要加上 readonly覆旭,確保是只讀狀態(tài)。
當(dāng)然如果你就是喜歡直接改變狀態(tài)岖妄,那么也可以不加readonly型将。
setUser
這里有兩個注意點。
一個是要加到 inject 獲取出來的狀態(tài)上荐虐,否則就是只能改變本組件的狀態(tài)七兜,除非你在跟組件改狀態(tài)。
另一個就是應(yīng)為用的是 reactive福扬,所以不能直接賦值的方式來修改腕铸,但是一個一個屬性修改也太麻煩了,所以這里采用 Object.assign(_user, user) 的方式來修改屬性铛碑。
這是ES6提供的一種方法狠裹,用后面的對象的屬性,覆蓋前面的對象的屬性汽烦。
注意:這種方法有可能導(dǎo)致增加屬性涛菠。
使用 Symbol 避免重名
export const sysUserInfo = Symbol('userOnlineInfo')
一開始我沒把這個寫在 單獨(dú)的js文件里面,但是發(fā)現(xiàn)子組件里面讀取不出來狀態(tài),所以只好把 Symbol 放在單獨(dú)的js文件里面了俗冻。
一開始用他是想徹底堵住直接修改狀態(tài)的漏洞礁叔,但是發(fā)現(xiàn)好像還是不行。
所以現(xiàn)在就變成了避免重名迄薄、避免“魔術(shù)”的功能琅关。
似乎應(yīng)該用純大寫字母來命名,但是讥蔽,英語重來沒及格過涣易,看純大寫的實在頭疼。如果你們喜歡的話勤篮,你們可以用都毒。
反正組件里面也看不到。
根組件注入
import userState from './store-nf'
setup () {
const { userInfo, register } = userState()
// 在這個組件里面注入碰缔,子組件里面可以共享狀態(tài)
register()
setTimeout(() => {
userInfo.userCode = '222222' // 只讀狀態(tài)账劲,不會修改,F(xiàn)12會給出警告金抡。
console.log('userInfo--定時修改', userInfo)
}, 500)
}
子組件調(diào)用
import userState from '../store-nf'
setup () {
const { userInfo, getUser } = userState()
// 測試控件內(nèi)部修改
const test = getUser()
test.userNike = '4345555' // 只讀瀑焦,不讓改。
// 使用指定的方法修改狀態(tài)
setUser({ userCode: '22222' })
}
基本思路就是這樣梗肝。
現(xiàn)在這個樣子還是比較簡陋榛瓮,大概會有一些不足的地方。
模塊化
這樣使用本身就變成了一個個獨(dú)立的模塊巫击,或者是一個個獨(dú)立的管理類禀晓。
如果都是在根組件里面注入的話,那么就都是兄弟模塊坝锰,沒有上下級關(guān)系粹懒。
如果在不同的組件里面注入,那么依賴組件的層級關(guān)系來確定上下級的關(guān)系顷级。
這樣就避免的Vuex里面的模塊的命名空間的問題凫乖。
不過這樣也太分散了,是不是有點不便于統(tǒng)一管理呢弓颈?