简单了解一下pinia的结构
随着 Vue3 的正式转正,Pinia 也渐渐火了起来。所以要更新一下自己的知识树了。这里主要是看看新的状态是什么“形态”。状态的容器还是“reactive”
- 按照官网教程,做一个简单的例子:
import { defineStore } from 'pinia'export const usePersonStore = defineStore('objectTest', {
state: () => {
return {
name: 'jyk',
age: 18,
info: {
a1: '11',
a2: '22'
}
}
},
// 也可以这样定义状态
// state: () => ({ count: 0 })
actions: {
nameAction() {
this.name += '11'
}
},
getters: {
ageTest(state) {
// 会有代码自动补全!
return state.age += 100
}
}
})
- 组件里引用:
import { usePersonStore } from './object.js'const xiaoming = usePersonStore()console.log('\n xiaoming:')
console.dir(xiaoming)
console.log('counter - keys :')
console.log(Object.keys(xiaoming))console.log('counter - for in :')
for (const key in xiaoming){
console.log(key)
}
{{xiaoming}}
{{xiaoming.age}}
{{index}} -- {{key}}: {{item}}
- 然后看看效果
文章图片
状态果然采用了 reactive,只是内部结构有点茫然,为啥是这样?
数据部分变成了 ref,错,是 toRef 一开始看,是把数据部分变成了 ref,但是仔细一看,原理是toRef。好吧,大概是为了保证响应性,自动结构了。只是还是挺无语的。
有图为证:
文章图片
getter 变成了 computed 这个在意料之中,只是为啥和数据在一个“层级”上?
文章图片
action 和数据是一级的。 action 还是函数的形式,只是,应该挂在“原型”上面吧,为啥又和数据挤在一起了?
文章图片
状态是否需要遍历? 为啥这么在意 getter、action是不是和数据在一个“层级”上呢?因为我经常使用遍历的方式。
试了一下,果然都出来了。
如果在使用状态的时候,不需要用到遍历的话,可以跳过。
template 模板 整体使用
{{xiaoming}}
- 结果:
{ "$id": "objectTest", "name": "jyk", "age": 118, "info": { "a1": "11", "a2": "22" }, "ageTest": 118 }
- 讨论
出现了$id和数据成员,虽然没有出现 getter,但是被执行了一次。
所以age变成了“118”。
好吧,可能是我的用法不对。
{{xiaoming.age}}
不会触发getter,age还是 18
{{xiaoming.age}}
{{xiaoming.ageTest}}
两个都显示为 “118”
v-for
{{index}} -- {{key}}: {{item}}
- 结果
0 -- $id: objectTest
1 -- $onAction: function () { [native code] }
2 -- $patch: function $patch(partialStateOrMutator) { let subscriptionMutation;
isListening = false;
if (true) { debuggerEvents = [];
} if (typeof partialStateOrMutator === "function") { partialStateOrMutator(pinia.state.value[$id]);
subscriptionMutation = { type: MutationType.patchFunction, storeId: $id, events: debuggerEvents };
} else { innerPatch(pinia.state.value[$id], partialStateOrMutator);
subscriptionMutation = { type: MutationType.patchObject, payload: partialStateOrMutator, storeId: $id, events: debuggerEvents };
} isListening = true;
triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]);
}
3 -- $reset: function $reset() { const newState = state ? state() : {};
this.$patch(($state) => { assign($state, newState);
});
}
4 -- $subscribe: $subscribe(callback, options2 = {}) { if (typeof options2 === "boolean") { console.warn(`[\u{1F34D}]: store.$subscribe() no longer accepts a boolean as the 2nd parameter: Replace "store.$subscribe(fn, ${String(options2)})" with "store.$subscribe(fn, { detached: ${String(options2)} })". This will fail in production.`);
options2 = { detached: options2 };
} const _removeSubscription = addSubscription(subscriptions, callback, options2.detached);
const stopWatcher = scope.run(() => watch(() => pinia.state.value[$id], (state, oldState) => { if (isListening) { callback({ storeId: $id, type: MutationType.direct, events: debuggerEvents }, state);
} }, assign({}, $subscribeOptions, options2)));
const removeSubscription = () => { stopWatcher();
_removeSubscription();
};
return removeSubscription;
}
5 -- $dispose: function $dispose() { scope.stop();
subscriptions = [];
actionSubscriptions = [];
pinia._s.delete($id);
}
6 -- name: jyk
7 -- age: 118
8 -- info: { "a1": "11", "a2": "22" }
9 -- nameAction: function() { const _actionId = runningActionId;
const trackedStore = new Proxy(store, { get(...args) { activeAction = _actionId;
return Reflect.get(...args);
}, set(...args) { activeAction = _actionId;
return Reflect.set(...args);
} });
return actions[actionName].apply(trackedStore, arguments);
}
10 -- ageTest: 118
11 -- _hotUpdate: function(newStore) { originalHotUpdate.apply(this, arguments);
patchActionForGrouping(store, Object.keys(newStore._hmrPayload.actions));
}
好吧,大概是我的使用方式不对。
for in
console.log('counter - for in :')
for (const key in xiaoming){
console.log(key)
}
- 结果
counter - for in :
pinia.vue:42 $id
pinia.vue:42 $onAction
pinia.vue:42 $patch
pinia.vue:42 $reset
pinia.vue:42 $subscribe
pinia.vue:42 $dispose
pinia.vue:42 name
pinia.vue:42 age
pinia.vue:42 info
pinia.vue:42 nameAction
pinia.vue:42 ageTest
pinia.vue:42 _hotUpdate
- 讨论
没有出现 action。出现了内部设置的成员,以及数据、getter。总之和我想的不一样。
console.log('counter - keys :')
console.log(Object.keys(xiaoming))
- 结果
counter - keys :
pinia.vue:38 (12) ["$id", "$onAction", "$patch", "$reset", "$subscribe", "$dispose", "name", "age", "info", "nameAction", "ageTest", "_hotUpdate"]
我想的到底是啥样的呢? 可以使用 class + reactive 实现一个充血实体类,比如这样:
import { computed, reactive } from 'vue'// 充血实体类
class TestClass {
constructor (_info) {
// 设置属性,数组或者对象
this.name = 'jyk'
this.age = 18
this.info = {
a1: 'a1',
a2: 'a2'
}
}
// 通用赋值
$set(model, clear = false) {
if (clear) {
Object.keys(this).forEach(key => {
delete this[key]
})
}
Object.assign(this, model)
}
actionTest() {
this.age += 1
}
get getterTest() {
const tmp = computed(() => { return this.age + 100})
return tmp
}
}export default function() {
const tmp = new TestClass()
return reactive(tmp)
}
在组件里使用:
const test2 = testClass()console.log(test2)
console.log(test2.getterTest)
console.log('\n 遍历 Object.keys -----')
console.log(Object.keys(test2))
console.log('\n 遍历 for in -----')
for (const key in test2) {
console.log(key, ':', test2[key])
}
console.log('\n 遍历 for in 结束 -----')
获取实例后,套上 reactive 就可以获得响应性。
这样数据部分在第一层,其他各种方法都在“原型”里面,那么在 v-for、 Object.keys 和for...in的时候,只会出现数据部分,没有各种函数了。
整体结构也很简洁。
- 看看打印效果
文章图片
遍历的情况也是挺好的。
推荐阅读
- 基于C语言实现简单五子棋游戏
- 提的最多的数据库“索引”,先来简单了解一下
- Android|Android 12(S) 图形显示系统 - 简单聊聊 SurfaceView 与 BufferQueue的关联(十三)
- python|网络图片爬虫(几个简单步骤实现网页图片的爬取,详细步骤,超详细,简单易懂)
- Pytorch|超最简单的安卓端深度学习模型部署教程——pytorch2onnx2pdinfer2android
- Python全栈系列[更新中]|Python零基础入门篇 - 33 - 你了解编程范式吗(面向过程编程与面向对象编程的区别又是什么?)
- 架构师成长之路也该了解的新一代微服务技术-ServiceMesh(上)
- Java实现简单班级管理系统
- 设计模式学习笔记(三)简单工厂、工厂方法和抽象工厂之间的区别
- react中的axios模块你了解吗