从pinia源码中能学到什么

1 前言

真的好久好久没写文章了,看了下发帖记录,上次还是半年前,这半年真的发生了太多的事,对这个社会有了新的理解和想法,也重新审视了下自己,决定重新出发,重拾起键盘,做个总结。

我毕业之后就开始使用React做为主要前端框架进行开发任务,中途跳槽到一家公司用了几个月的Vue2,当时整天就是写增删改查,觉得没意思就走了,下一家继续回归React,最近几个月由于公司业务需要,切换到Vue3开发,但是因为对Vue不熟悉,做一些"骚操作"的时候会感觉格外的力不从心,不知道这么写好不好,会不会出问题。之前看了类React框架的源码就让我对React有了深刻的理解(官方React还没看,打算之后有时间再看),所以源码还是要看的。

需要注意的是,看源码并不是为了让你有吹牛逼的资本,而是让你在遇到具体问题的时候有具体解决方案,并且知道这么干一定是没错的。而不是为什么会这样呢,不知道诶,反正做出来了,搞不懂,就这样吧。如果你看过源码,能非常自信的说,这么干一定行!什么,不行?我的前端崩塌了,尤雨溪又搞了什么骚操作!

之前写源码文章说实话我就是在写流水账,什么多少多少行实现一个啥,然后把代码贴出来,我现在感觉没啥必要,因为会去看源码的人不需要你的流水账,不会去看源码的人也看不懂或者也不关心你怎么实现的。所以现在,我打算写我看了一个库的源码,我学到了一些什么东西,因为我才用Vue3没多久,算是一个Vue小白,所以如果写了一些很基础的内容,请大神轻喷。那么今天先从pinia的源码开始

2 知识点

2.1 effectScope

2.1.1 什么是effectScope

能用于管理某个作用域下的所有副作用,并对其进行统一的处理

ts 复制代码
let count1 = ref(0)

// 创建一个响应式作用域
const scope1 = effectScope()

scope1.run(() => {
  
  watch(count1, v => {
    console.log('xxx count1 changed', v)
  })

})

// 触发watch
count1.value++

queueMicrotask(() => {

  // 关闭监听
  scope1.stop()

  queueMicrotask(() => {
    // 下面就不会触发监听了(全部解除绑定)
    count1.value++
  })

})

2.1.2 effectScope与effectScope嵌套

需要知道的是,effectScope出现的目的是方便库给响应式做一次性接触监听绑定,那么如果scopescope互相嵌套,那么只需要取消第一个scope的监听,所有子scope也会全部接触监听,类似子组件卸载

ts 复制代码
let count1 = ref(0)
let count2 = ref(0)

// 创建一个响应式作用域
const scope1 = effectScope()

scope1.run(() => {
  
  let scope2 = effectScope()

  watch(count1, v => {
    console.log('xxx count1 changed', v)
  })
  
  scope2.run(() => {
    watch(count2, v => {
      console.log('xxx count2 changed', v)
    })
  })


})

// 触发watch
count1.value++
count2.value++

queueMicrotask(() => {

  // 关闭监听
  scope1.stop()

  queueMicrotask(() => {
    count1.value++    // 不会触发watch
    count2.value++    // 不会触发watch
  })

})

2.1.3 detached

创建effectScope作用域的时候可以传入一个参数,这个值默认是false,这个参数可以让互相嵌套的scope断开关系

ts 复制代码
function effectScope(detached?: boolean): EffectScope;
ts 复制代码
let count1 = ref(0)
let count2 = ref(0)

// 创建一个响应式作用域
const scope1 = effectScope()

scope1.run(() => {
  
  let scope2 = effectScope(true)

  watch(count1, v => {
    console.log('xxx count1 changed', v)
  })
  
  scope2.run(() => {
    watch(count2, v => {
      console.log('xxx count2 changed', v)
    })
  })


})

// 触发watch
count1.value++
count2.value++

queueMicrotask(() => {

  // 关闭监听
  scope1.stop()
  console.log('关闭监听')

  queueMicrotask(() => {
    count1.value++    // 不会触发watch
    count2.value++    // 会触发watch
  })

})

2.1.4 effectScope.run的返回值

effectScope的目的是为了给setup中的所有监听解绑,那么setup有个特性,就是返回值可以被模板使用到,那么effectScope同理,run的返回值就是函数执行的返回值

ts 复制代码
const scope1 = effectScope()

console.log(scope1.run(() => {

  return 1

}))   // 1

2.2 runWithContext

允许在非setup中访问inject,如果你需要开发Vue相关的库,同一个页面中存在多个实例,但是你的方法却是公用的,那么这个api会非常的有用,这防止了单例的诞生,而且全局可以公用同一个方法,我们来看下面的例子

ts 复制代码
import { type App, createApp } from 'vue'

const testSymbol = Symbol() 

const myPlugin = {
  install(app: App) {
    app.provide(testSymbol, { test: 'testData' })
    console.log(inject(testSymbol))    // undefined
    app.runWithContext(()=>{
      console.log(inject(testSymbol))  // { test: 'testData' }
    })
  }
}

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

2.3 es module变量可修改

其实这个特性我很早就知道,是为了让更多的人知道(为了凑字数),尤雨溪似乎特别喜欢使用这个特性,Vue源码中很多地方都用到

比如现在有下面一个模块,导出了一个 count 变量

  • test.js
ts 复制代码
export let count = 1

我们是不能在别的模块中去修改count的值的

ts 复制代码
import { count } from './test.js'

try {
  count++
} catch (e) {
  console.log(e)  // TypeError: Assignment to constant variable.
}

但是,我们却可以调用test.js中的方法,去修改count的值

js 复制代码
export let count = 1

export function add(){
  count++
}
js 复制代码
import { count, add } from './test.js'

console.log(count)  // 1
try {
  count++
} catch (e) {
  console.log(e)  // TypeError: Assignment to constant variable.
}
add()
console.log(count)  // 2
相关推荐
Cool----代购系统API16 分钟前
css设置盒子动画,CSS3 transition动画 animation动画
前端·css·css3
哟哟耶耶26 分钟前
css-设置元素的溢出行为为可见overflow: visible;
前端·css
sunly_29 分钟前
CSS:跑马灯
前端·css
2301_8187320637 分钟前
用layui表单,前端页面的样式正常显示,但是表格内无数据显示(数据库连接和获取数据无问题)——已经解决
java·前端·javascript·前端框架·layui·intellij idea
yqcoder38 分钟前
npm link 作用
前端·npm·node.js
林涧泣43 分钟前
【Uniapp-Vue3】页面和路由API-navigateTo及页面栈getCurrentPages
前端·vue.js·uni-app
Komorebi゛1 小时前
【uniapp】获取上传视频的md5,适用于APP和H5
前端·javascript·uni-app
林涧泣1 小时前
【Uniapp-Vue3】动态设置页面导航条的样式
前端·javascript·uni-app
杰九1 小时前
【全栈】SprintBoot+vue3迷你商城(10)
开发语言·前端·javascript·vue.js·spring boot
Hopebearer_2 小时前
入门 Canvas:Web 绘图的强大工具
前端·javascript·es6·canva可画