Vue3——pinia部分(小满版本)(二)

简介: Vue3——pinia部分(小满版本)

Vue3——pinia部分(小满版本)(一)https://developer.aliyun.com/article/1470384

第四章 — 结构store - 源码解析

在pinia是不允许直接解构,是会失去响应式的

const Test = useTestStore()
 //pinia解构不具有响应式
const { current, name } = Test//这是解构
 
console.log(current, name);

差异对比

修改 Test current 解构完之后的数据不会变


而源数据是会变的

<template>
  <div>origin value"这是不解构的"{{Test.current}}</div>
  <div>
    pinia:{{ current }}--{{ name }}//这是解构的,从Test中解构出来,直接使用,不在前面加Test
    change :
    <button @click="change">change</button>
  </div>
</template>
  
<script setup lang='ts'>
import { useTestStore } from './store'
 
const Test = useTestStore()
 
const change = () => {
   Test.current++
}
 
const { current, name } = Test
 
console.log(current, name);
 
 
</script>
  
<style>
</style>

解决方案可以使用 storeToRefs

import { storeToRefs } from 'pinia'
 
const Test = useTestStore()
 
const { current, name } = storeToRefs(Test)//在解构之前先包一层

其原理跟 toRefs 一样的给里面的数据包裹一层 toref


源码 通过 toRaw 使 store 变回原始数据防止重复代理(这个在前面Vue3基础部分的源码部分有讲过为什么会发生重复代理的,可以翻一翻


Vue3基础笔记(小满版本))


循环 store 通过 isRef isReactive 判断 如果是响应式对象直接拷贝一份给 refs 对象 将其原始对象包裹 toRef 使其变为响应式对象

源码解析 - storeToRefs

//源码
function storeToRefs(store) {
    // See https://github.com/vuejs/pinia/issues/852
    // It's easier to just use toRefs() even if it includes more stuff
    if (isVue2) {
        // @ts-expect-error: toRefs include methods and others
        console.log("store变化之前",store)
        return toRefs(store);
        //- 刚开始就先判断一个是不是对象,是的话将其里面的值放到数组中初始化一下(ps:真的很严谨)
    //然后每个属性去做一下toRef,然后把这个内容做一个返回。也判断了一下是不是Proxy对象。如果是Proxy对象就走下面的那个判断了
        console.log("store变化之后",store)
    }
    else {
        store = toRaw(store);//将store转化为原始对象,toRaw把reactive套上的Proxy外壳给脱掉了
        const refs = {};
        for (const key in store) {//for循环做了一个toRef的一个操作
            const value = store[key];//拷贝(复制)了一层store
            if (isRef(value) || isReactive(value)) {
                // @ts-expect-error: the key is state or getter
                refs[key] =
                    // ---
                    toRef(store, key);//然后进行包裹
            }
        }
        return refs;
    }
}

相较于小满录制视频的3月份来说,制作笔记的时间是同年11月份,此时pinia已经进行了优化,源码部分对Vue2进行了一个兼容,我根据自己的理解重新写上了注释

第五章 — Actions,getters

Actions(支持同步异步)

1.同步

同步 直接调用即可

//商店store下的index.ts文件
import { defineStore } from 'pinia'
import { Names } from './store-naspace'
export const useTestStore = defineStore(Names.TEST, {
    state: () => ({
        counter: 0,
    }),
    actions: {
        increment() {
            this.counter++
        },
        randomizeCounter() {
            this.counter = Math.round(100 * Math.random())//同步写法,直接使用即可
        },
    },
})
<template>
     <div>
         <button @click="Add">+</button>
          <div>
             {{Test.counter}}
          </div>    
     </div>
</template>
 
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
     Test.randomizeCounter()//直接就是进行一个调用,这里的Test是对从store中解构出来的userTestStore的一个调用
}
 
</script>
 
<style>
 
</style>

2.异步

异步 可以结合 async await 修饰


Promise 的构造函数接收一个参数,是函数,并且传入两个参数:resolvereject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。其实这里用 “成功” 和 “失败” 来描述并不准确,按照标准来讲,resolve 是将 Promise 的状态置为 fullfiled,reject 是将 Promise 的状态置为 rejected。不过在我们开始阶段可以先这么理解

import { defineStore } from 'pinia'
import { Names } from './store-naspace'
 
type Result = {
    name: string
    isChu: boolean
}
 
const Login = (): Promise<Result> => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve({
                name: '小满',
                isChu: true
            })
        }, 3000)
    })
}
 
export const useTestStore = defineStore(Names.TEST, {
    state: () => ({
        user: <Result>{},//定义泛型
        name: "123"
    }),
    actions: {
        async getLoginInfo() {//异步操作
            const result = await Login()//调用了上面的Login异步操作
            this.user = result;
            this.user = setName("大飞机")//
        },
        setName(name:string){
            this.name = name;
        }
    },
})

template

<template>
     <div>
         <button @click="Add">test</button>
          <div>
             {{Test.user}}
          </div>    
     </div>
</template>
 
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
     Test.getLoginInfo()
}
 
</script>
 
<style>
 
</style>

3.多个 action 互相调用 getLoginInfo setName

state: () => ({
        user: <Result>{},
        name: "default"
    }),
    actions: {
        async getLoginInfo() {
            const result = await Login()
            this.user = result;
            this.setName(result.name)
        },
        setName (name:string) {
            this.name = name;
        }
    },

getters

在使用 this 访问时,需要定义返回类型(在 TypeScript 中),这是因为 TypeScript 中的一个已知限制 这不会影响使用箭头函数定义的 getter,也不会影响不使用 this 的 getter

1.箭头函数

  1. 使用箭头函数不能使用 this this 指向已经改变指向 undefined 修改值请用 state
    主要作用类似于 computed 数据修饰并且有缓存
  2. Getter 完全等同于 Store 状态的计算值,在 defineStore () 中的 getters 属性中定义
    当它接收 “状态” 作为第一个参数时,鼓励箭头函数的使用
getters:{
       newPrice:(state)=>  `$${state.user.price}`
    },

2.普通函数

  1. 普通函数形式可以使用 this
  2. getter 只会依赖状态,可能会使用到其他 getter,因此可以在定义常规函数时通过 this 访问到整个 store 的实例
getters:{
       newCurrent ():number {
           return ++this.current
       }
    },

3.getters 互相调用

与计算属性一样,可以组合多个 getter。通过 this 访问任何其他 getter

getters:{
       newCurrent ():number | string {
           return ++this.current + this.newName
       },
       newName ():string {
           return `$-${this.name}`
       }
    },

第六章 —(API)

1.$reset

重置store到他的初始状态

state: () => ({
     user: <Result>{},
     name: "default",
     current:1
}),

Vue 例如我把值改变到了 10

const change = () => {
     Test.current++
}

视频写法

const reset = ()=>{
    Test.$reset()
}//直接进行初始化,调用reset即可

调用 $reset ();


将会把 state 所有值 重置回 原始状态

2. 订阅 state 的改变

类似于 Vuex 的 abscribe 只要有 state 的变化就会走这个函数

Test.$subscribe((args,state)=>{//subscribe是订阅的意思
   console.log(args,state);//返回两个值如下
})

返回值

image.png

第二个参数

如果你的组件卸载之后还想继续调用请设置第二个参数


第二个参数是一个对象 {detached: true},在组件销毁后依然监听状态的改变

Test.$subscribe((args,state)=>{
   console.log(args,state);
   
},{
  detached:true
})

3. 订阅 Actions 的调用

只要有 actions 被调用就会走这个函数


第一个参数是工厂函数(就是返回的是一个对象的)

Test.$onAction((args)=>{
   console.log(args);
   args.after(()=>{
       console.log('after');
   })
})
//args能够捕获到外面写入的数据内容
//App.vue文件(就是你使用pinia的文件,不一定是App.vue)
const change = ()=>{
    Test.setUser('123')//被args捕获到
}

image.png

第七章 — pinia插件

pinia 和 vuex 都有一个通病 页面刷新状态会丢失


我们可以写一个 pinia 插件缓存他的值

const __piniaKey = '__PINIAKEY__'
//定义兜底变量
 
 
type Options = {
   key?:string
}
//定义入参类型
 
 
 
//将数据存在本地
const setStorage = (key: string, value: any): void => {//设置的存储函数
 
localStorage.setItem(key, JSON.stringify(value))
 
}
 
 
//存缓存中读取
const getStorage = (key: string) => {
 
return (localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key) as string) : {})//判断有没有key,没有就返回空对象
 
}
 
 
//利用函数柯丽华接受用户入参
const piniaPlugin = (options: Options) => {
 
//将函数返回给pinia  让pinia  调用 注入 context
return (context: PiniaPluginContext) => {
 
const { store } = context;
 
const data = getStorage(`${options?.key ?? __piniaKey}-${store.$id}`)//将数据取出来
 
store.$subscribe(() => {
 
setStorage(`${options?.key ?? __piniaKey}-${store.$id}`, toRaw(store.$state));//
 
})
 
//返回值覆盖pinia 原始值
return {
 
...data
 
}
 
}
 
}
 
//初始化pinia
const pinia = createPinia()
 
//注册pinia 插件
pinia.use(piniaPlugin({
key: "pinia"
}))


目录
相关文章
|
1天前
Vue3 项目的 setup 函数
【10月更文挑战第23天】setup` 函数是 Vue3 中非常重要的一个概念,掌握它的使用方法对于开发高效、灵活的 Vue3 组件至关重要。通过不断的实践和探索,你将能够更好地利用 `setup` 函数来构建优秀的 Vue3 项目。
|
1天前
|
存储 JavaScript 前端开发
vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
【10月更文挑战第21天】 vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
|
4天前
|
API
vue3知识点:reactive对比ref
vue3知识点:reactive对比ref
15 3
|
4天前
|
JavaScript API
vue3知识点:ref函数
vue3知识点:ref函数
13 2
|
4天前
|
JavaScript API
Vue3快速上手简介
Vue3快速上手简介
15 2
|
4天前
|
API
vue3知识点:reactive函数
vue3知识点:reactive函数
11 1
|
4天前
|
JavaScript 前端开发 API
vue3知识点:Vue3.0中的响应式原理和 vue2.x的响应式
vue3知识点:Vue3.0中的响应式原理和 vue2.x的响应式
11 0
5分钟上手Vue+ts+vite+pinia
5分钟上手Vue+ts+vite+pinia
715 0
|
2天前
|
数据采集 监控 JavaScript
在 Vue 项目中使用预渲染技术
【10月更文挑战第23天】在 Vue 项目中使用预渲染技术是提升 SEO 效果的有效途径之一。通过选择合适的预渲染工具,正确配置和运行预渲染操作,结合其他 SEO 策略,可以实现更好的搜索引擎优化效果。同时,需要不断地监控和优化预渲染效果,以适应不断变化的搜索引擎环境和用户需求。
|
2天前
|
缓存 JavaScript 搜索推荐
Vue SSR(服务端渲染)预渲染的工作原理
【10月更文挑战第23天】Vue SSR 预渲染通过一系列复杂的步骤和机制,实现了在服务器端生成静态 HTML 页面的目标。它为提升 Vue 应用的性能、SEO 效果以及用户体验提供了有力的支持。随着技术的不断发展,Vue SSR 预渲染技术也将不断完善和创新,以适应不断变化的互联网环境和用户需求。
20 9