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"
}))


目录
相关文章
|
2月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
143 64
|
10天前
|
JavaScript API 数据处理
vue3使用pinia中的actions,需要调用接口的话
通过上述步骤,您可以在Vue 3中使用Pinia和actions来管理状态并调用API接口。Pinia的简洁设计使得状态管理和异步操作更加直观和易于维护。无论是安装配置、创建Store还是在组件中使用Store,都能轻松实现高效的状态管理和数据处理。
39 3
|
2月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
39 8
|
2月前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
33 1
|
2月前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
42 1
|
2月前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
5分钟上手Vue+ts+vite+pinia
5分钟上手Vue+ts+vite+pinia
733 0
|
4天前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
41 1
|
15天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
2月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
46 1
vue学习第一章

热门文章

最新文章