Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >简单了解一下pinia的结构

简单了解一下pinia的结构

作者头像
用户1174620
发布于 2022-05-09 11:40:37
发布于 2022-05-09 11:40:37
52400
代码可运行
举报
运行总次数:0
代码可运行

随着 Vue3 的正式转正,Pinia 也渐渐火了起来。所以要更新一下自己的知识树了。这里主要是看看新的状态是什么“形态”。

状态的容器还是“reactive”

  • 按照官网教程,做一个简单的例子:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
    }
  }
})
  • 组件里引用:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   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)
   }
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{{xiaoming}}<br>
{{xiaoming.age}}<br>

  <div v-for="(item, key, index) in xiaoming">
    {{index}} -- {{key}}: {{item}}
  </div>
  • 然后看看效果

状态果然采用了 reactive,只是内部结构有点茫然,为啥是这样?

数据部分变成了 ref,错,是 toRef

一开始看,是把数据部分变成了 ref,但是仔细一看,原理是toRef。好吧,大概是为了保证响应性,自动结构了。只是还是挺无语的。

有图为证:

getter 变成了 computed

这个在意料之中,只是为啥和数据在一个“层级”上?

action 和数据是一级的。

action 还是函数的形式,只是,应该挂在“原型”上面吧,为啥又和数据挤在一起了?

状态是否需要遍历?

为啥这么在意 getter、action是不是和数据在一个“层级”上呢?因为我经常使用遍历的方式。 试了一下,果然都出来了。

如果在使用状态的时候,不需要用到遍历的话,可以跳过。

template 模板

整体使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{{xiaoming}}
  • 结果:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{ "$id": "objectTest", "name": "jyk", "age": 118, "info": { "a1": "11", "a2": "22" }, "ageTest": 118 }
  • 讨论 出现了$id和数据成员,虽然没有出现 getter,但是被执行了一次。 所以age变成了“118”。 好吧,可能是我的用法不对。

分开使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{{xiaoming.age}}<br><br>

不会触发getter,age还是 18

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{{xiaoming.age}}<br><br>
{{xiaoming.ageTest}}<br><br>

两个都显示为 “118”

v-for

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  <div v-for="(item, key, index) in xiaoming">
    {{index}} -- {{key}}: {{item}}
  </div>
  • 结果
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    console.log('counter - for in :')
    for (const key in xiaoming){
      console.log(key)
    }
  • 结果
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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。总之和我想的不一样。

Object.keys

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    console.log('counter - keys :')
    console.log(Object.keys(xiaoming))
  • 结果
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
counter - keys :
pinia.vue:38 (12) ["$id", "$onAction", "$patch", "$reset", "$subscribe", "$dispose", "name", "age", "info", "nameAction", "ageTest", "_hotUpdate"]

我想的到底是啥样的呢?

可以使用 class + reactive 实现一个充血实体类,比如这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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)
}

在组件里使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  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的时候,只会出现数据部分,没有各种函数了。

整体结构也很简洁。

  • 看看打印效果

遍历的情况也是挺好的。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
pinia核心笔记
记录pinia核心源码阅读笔记,这里跳过hmr(热更新), mapHelpers(class 工具)等工具源码。 剔除的部分vue2.0兼容代码。 当前pinia版本2.0.13
copy_left
2022/05/13
1.1K0
pinia核心笔记
被迫开始学习Typescript —— class
TS 的 class 看起来和 ES6 的 Class 有点像,基本上差别不大,除了 可以继承(实现)接口、私有成员、只读等之外。
用户1174620
2022/05/18
4020
被迫开始学习Typescript —— class
2023前端二面必会vue面试题指南4
早期的前端路由的实现就是基于 location.hash 来实现的。其实现原理很简单,location.hash 的值就是 URL中 # 后面的内容。比如下面这个网站,它的 location.hash 的值为 '#search'
bb_xiaxia1998
2023/01/06
6220
Pinia状态管理器学习笔记,持续记录
官方文档:https://pinia.vuejs.org/ 中文文档:https://pinia.web3doc.top/
房东的狗丶
2023/02/17
1.6K0
Pinia入门-实现简单的用户状态管理
在整个应用程序中访问的数据(且不需要被持久化),例如导航栏中显示的用户信息,以及需要通过页面保留的数据,例如一个非常复杂的多步骤表格。
luciozhang
2023/04/22
7440
【Vue3+TypeScript】CRM系统项目搭建之 — 关于 VUE3 语法新变化
vite 是新一代前端构建工具,官网地址:https://vitejs.cn,vite的优势如下:
HelloWorldZ
2024/03/20
5310
【Vue3+TypeScript】CRM系统项目搭建之 — 关于 VUE3 语法新变化
欧耶!Pinia 正式成为 vuejs 的一员
Pinia 正式成为 vuejs 官方的状态库,意味着 🍍 就是 Vuex 5.x 。 先来看早期 vue 上一个关于 Vuex 5.x 的 RFC : 描述中可以看到,Vue 5.x 主要改善以下几个特性: 同时支持 composition api 和 options api 的语法; 去掉 mutations,只有 state、getters 和 actions; 不支持嵌套的模块,通过组合 store 来代替; 更完善的 Typescript 支持; 清晰、显式的代码拆分; 而 Pinia
码农小余
2022/06/16
6670
欧耶!Pinia 正式成为 vuejs 的一员
告别Vuex,发挥compositionAPI的优势,打造Vue3专用的轻量级状态 定义main.jscontroller组件设置监听和钩子局部状态
Vuex 是基于 Vue2 的 option API 设计的,因为 optionAPI 的一些先天问题,所以导致 Vuex 不得不用各种方式来补救,于是就出现了 getter、mutations、action、module、mapXXX 这些绕圈圈的使用方式。想要使用 Vuex 就必须先把这些额外的函数给弄明白。
用户1174620
2021/10/20
1.1K0
校招前端二面高频vue面试题
在Vue中,对响应式处理利用的是Object.defineProperty对数据进行拦截,而这个方法并不能监听到数组内部变化,数组长度变化,数组的截取变化等,所以需要对这些操作进行hack,让Vue能监听到其中的变化。 那Vue是如何实现让这些数组方法实现元素的实时更新的呢,下面是Vue中对这些方法的封装:
bb_xiaxia1998
2022/12/20
1.5K0
pinia基本使用介绍
比如开始的时候我们可以使用缓存进行同步数据,虽然很low但是它确实属于一种方案,但是这种方案的实时性很差,也就是很难做到信息的及时同步,虽然你可以写很多监听来达到一个同步的效果,但是代码维护起来就会很笨重
何处锦绣不灰堆
2022/09/21
9050
vue3.0 源码解析一 :响应式原理(上)
从本文开始,我们正式进入vue3.0 源码解析流程。个人觉得从ceateApp入手并不是最佳的学习方案,所以我们先从composition-api响应式原理入手,共同学习vue3.0带来的哪些翻天覆地的变化。
用户6835371
2021/06/01
5650
vue3.0 源码解析一 :响应式原理(上)
美团前端vue面试题_2023-05-19
Vue3最重要更新之一就是Composition API,它具有一些列优点,其中不少是针对Options API暴露的一些问题量身打造。是Vue3推荐的写法,因此掌握好Composition API应用对掌握好Vue3至关重要
用户10358241
2023/05/19
1K0
聊聊Vuex原理
在调用 Vuex 的时候会找其 install 方法,并把组件实例传递到 install 方法的参数中。
yyds2026
2022/10/10
3720
结合 Vuex 和 Pinia 做一个适合自己的状态管理 nf-state
结合 Vuex 和 Pinia, 保留需要的功能,去掉不需要的功能,修改一下看着不习惯的使用方法,最后得到了一个满足自己需要的轻量级状态管理 —— nf - state。
用户1174620
2022/05/12
9580
结合 Vuex 和 Pinia 做一个适合自己的状态管理 nf-state
实现一个简单版 Vue2 双向数据绑定
实现一个简单版本 Vue,仅实现了 数据响应式、依赖收集、compile编译中的html和文本编译,起名为nvue,即新 vue。
蓓蕾心晴
2022/09/24
2160
实现一个简单版 Vue2 双向数据绑定
【Vue工程】006-Pinia
https://stackblitz.com/github/piniajs/example-vue-3-vite?file=README.md
訾博ZiBo
2025/01/06
1710
一文梳理vue面试题知识点
Vue3.x 改用 Proxy 替代 Object.defineProperty。因为 Proxy 可以直接监听对象和数组的变化,并且有多达 13 种拦截方法。
bb_xiaxia1998
2022/10/24
9590
Vuex 2.0 源码分析
通常,在项目不是很复杂的时候,我们会利用全局事件总线 (global event bus)解决,但是随着复杂度的提升,这些代码将变的难以维护。因此,我们需要一种更加好用的解决方案,于是,Vuex 诞生了。
前端迷
2019/08/06
2K0
Vuex 2.0 源码分析
前端系列15集-watch,watchEffect,eventBus
watchEffect,它立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。
达达前端
2023/10/08
5240
vue 随记(4):响应式的进化
正常来说,被监听的数据在初始化时就已经被全部监听了。后续并不会再次这种时候,不得不通过vm.$set(全局 Vue.set 的别名。)来处理新增的属性。
一粒小麦
2020/07/23
7010
vue 随记(4):响应式的进化
相关推荐
pinia核心笔记
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验