vue3探索——5分钟快速上手大菠萝pinia

这篇具有很好参考价值的文章主要介绍了vue3探索——5分钟快速上手大菠萝pinia。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

温馨提示:本文以vue3+vite+ts举例,vite配置和ts语法侧重较少,比较适合有vuex或者vue基础的小伙伴们儿查阅。

安装pinia

  • yarn
yarn add pinia
  • npm
npm install pinia
  • pnpm
pnpm add pinia

1-开始

方式一:在main.ts中直接引入pinia

src/main.ts 中引入pinia(根存储),并传递给应用程序。

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'

// 1-创建一个 pinia(根存储)
import { createPinia } from 'pinia'

const app = createApp(App)

// 2-告诉应用程序,我们将使用pinia
const pinia = createPinia();
// 以插件形式传递给app
app.use(pinia);

app.mount('#app');

方式二(推荐):单独开个.ts文件引入pinia

在根目录下新建文件夹,这里我命名为store,再在文件夹下新建一个index.ts文件(src/store/index.ts),用以配置和引入pinia。

// 1-创建一个 pinia(根存储)
import { createPinia } from 'pinia'

// 2-定义pinia实例
const pinia = createPinia();

// 3-暴露pinia实例
export default pinia;

然后在src/main.ts 中使用。

......
import pinia from '@/store/index.ts'
app.use(pinia);
......

其实和方式一没啥区别,只是为了保持main.ts文件整洁,并且方便配置pinia。

2-创建仓库

pinia与vuex差不多,相比于vuex,少了mutationmodules

pinia创建仓库,有选项式写法组合式写法

选项式Options API写法

在根目录下创建一个文件夹store (src/store),在store文件夹中可以创建你的仓库,比如下面我创建了一个名为user的仓库 (src/store/user.ts)。

// 选项式写法
// 1-引入api
import { defineStore } from "pinia";

// 2-定义仓库
const store = defineStore('user', {
    // 3-设置组件共享的状态,相当于组件的data
    state: () => ({
        userInfo: {
            name: '老刘',
            sex: '男',
            age: 17,
            isStudent: false
        },
        token: '5201314',
        password: '123456',
    }),
    // 3-设置状态计算值,相当于组件的computed
    getters: {
        name: (state) => state.userInfo.name,
        sex: (state) => state.userInfo.sex,
    },
    // 3-设置组件共享的方法,相当于组件的methods
    actions: {
        addAge() {
            // !!!这里可以使用this,访问当前仓库的state,getters,actions
            this.userInfo.age++;
            this.sayHaHa(); // 'HaHa!'
        },
        sayHaHa() {
            console.log('HaHa!');
        },
    }
});

// 最后别忘了把仓库暴露出去哦
export default store;

组合式Composition API写法(推荐)

上面的仓库 (src/store/user.ts)组合式写法如下:

// 组合式写法
// 1-引入pinia的api
import { defineStore } from "pinia";
// 2-引入vue3相关api
import { ref, reactive, computed } from 'vue';

// 3-定义仓库,注意第二个参数需要传入一个函数,函数需要返回一个对象!
const store = defineStore('user', () => {
    // 4-在这里面可以像在组件中一样,使用vue3的API,定义响应式数据
    const userInfo = reactive({
        name: '老刘',
        sex: '男',
        age: 17,
        isStudent: false
    });
    const token = ref('5201314');
    const password = ref('123456');

    // 这里computed的作用相当于getters
    const name = computed(() => userInfo.name);
    const sex = computed(() => userInfo.sex);

    // 4-还可以定义方法
    function addAge() {
        userInfo.age++;
    }

    // 5-然后把需要共享的数据或方法,装进一个对象,return出去
    return {
        userInfo,
        token,
        password,
        name,
        sex,
        addAge
    }
});

// 最后别忘了把仓库暴露出去哦
export default store;

TIP

还可以在仓库中使用watchwatchEffect等vue3的API喔~。

import { ref, reactive, computed, watch } from 'vue';
const store = defineStore('user', () => {
    const userInfo = reactive({
        age: 17,
    });
    // 使用vue3的watch()函数,可以对仓库状态进行监听
    watch(() => userInfo.age, (val) => {
        console.log(val);
    });
});

3-使用pinia

完成了上面的工作后,我们就可以在组件中愉快地使用pinia啦!

下面以src/App.vue作为示例。

(1)引入仓库

<template>

</template>

<script setup lang="ts">
// 1-引入刚刚自定义的仓库,模块名store 可以自定义
import store from '@/store/user.ts';

// 2-使用仓库,仓库实例名userStore 可以自定义
const userStore = store();
</script>

(2)在组件中访问仓库state和getters

在模板和script中,state和getters可以看作仓库实例(如userStore)的属性,直接加.访问即可。

<template>
    <div>
        <!-- 1-访问仓库的计算属性getters -->
        <span>姓名:{{ userStore.name }}</span>
        <span>性别:{{ userStore.sex }}</span>
        <!-- 1-访问仓库的状态state -->
        <span>年龄:{{ userStore.userInfo.age }}</span>
        <span>是否学生:{{ userStore.userInfo.isStudent ? '是' : '否' }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();

// 1-访问state和getters,类似于reactive响应式数据的访问
console.log('userStore', userStore);
console.log('姓名:', userStore.name);
console.log('性别:', userStore.sex);
console.log('年龄:', userStore.userInfo.age);
console.log('是否学生:', userStore.userInfo.isStudent ? '是' : '否');
</script>
输出
    userStore Proxy(Object) {$id: 'user', $onAction: ƒ, $patch: ƒ, $reset: ƒ, $subscribe: ƒ, …}[[Handler]]: Object[[Target]]: Object[[IsRevoked]]: false
    
    姓名: 老刘
    性别: 男
    年龄: 17
    是否学生: 否

(3)在组件中使用仓库actions

使用仓库方法与访问仓库state类似,仓库实例后直接加.调用即可。

<template>
    <div>
        <!-- 按钮点击,年龄+1 -->
        <button @click="onAddAge">年龄+1</button>
        <span>年龄:{{ userStore.userInfo.age }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();

// 按钮点击触发
function onAddAge() {
    // 1-使用仓库的actions
    userStore.addAge();
}
</script>

(4)修改state

直接修改

与vuex不同,pinia支持在组件中直接修改state

<template>
    <div>
        <!-- 按钮点击,年龄+1 -->
        <button @click="onAddAge">年龄+1</button>
        <span>年龄:{{ userStore.userInfo.age }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();

// 按钮点击触发
function onAddAge() {
    // 1-直接修改state
    userStore.userInfo.age++;
}
</script>

利用仓库actions进行修改

src/store/user.ts

......

const store = defineStore('user', () => {
    ......

    // 1-定义方法
    function addAge() {
        userInfo.age++;
    }

    // 2-return出去
    return {
        addAge
    }
});

// 3-导出仓库
export default store;

src/App.vue

<template>
    <div>
        <!-- 按钮点击,年龄+1 -->
        <button @click="onAddAge">年龄+1</button>
        <span>年龄:{{ userStore.userInfo.age }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();

// 按钮点击触发
function onAddAge() {
    // 4-使用仓库的方法
    userStore.addAge();
}
</script>

批量变更

通过仓库实例(如userStore)的 $patch 方法,可以对state同时应用多个更改。

<script setup lang="ts">
......

function changeState() {
    console.log(userStore.token); // '5201314'
    console.log(userStore.password); // '123456'

    // $patch()接收一个对象,对象内的属性是 需要变更的state
    // 注意是变更,新增state是无效的!
    userStore.$patch({
        token: '1024',
        password: '654321'
    });

    console.log(userStore.token); // '1024'
    console.log(userStore.password); // '654321'
}
</script>

上面的方法每次进行批量修改都需要传入一个新对象,有时候使用起来并不方便。下面是另一种写法,$patch接受一个函数来批量修改集合内部分对象。(推荐)

<script setup lang="ts">
......

function changeState() {
    // 这里的any是typescript的类型标注,可以不用理会
    // 回调函数的参数state就是 仓库目前的state
    userStore.$patch((state: any) => {
        state.token = '1024';
        state.password = '654321';
    });
}
</script>

整体替换(不推荐)

通过仓库实例(如userStore)的 $state 属性,来为新对象替换仓库的整个状态。

pinia官网提到整体替换state的方法,但并未说明是否保留数据响应式。经笔者实践,这种方法会丢失数据的响应式,所以不推荐使用

<script setup lang="ts">
......

function updateStore() {
    userStore.$state = {
        userInfo: {
            name: '老王',
            sex: '男',
            age: 66,
            isStudent: false
        }
    };
}
</script>

(5)重置state

通过调用仓库实例上的 $reset() 方法将状态重置到其初始值。

<script setup lang="ts">
......

function resetStore() {
    userStore.$reset();
}
</script>

$reset() 的坑

细心的你会发现,仓库state并没有重置,然后你打开你的的控制台,你会惊讶地发现它报了这么一个错误:

vue3探索——5分钟快速上手大菠萝pinia

这时候请你不要慌,先冷静地看一下报错信息。

这里翻译一下:Store "user"是使用setup语法构建的,不实现$reset()。(猜测是pinia的缺陷)

所以,根据报错信息,这里提供下面两种解决方案。

使用选项式Options API

使用选项式Options API编写pinia仓库,并且在组件中不能用script setup语法,要使用setup函数进行开发。

src/store/user.ts

......

// 使用选项式Options API编写仓库
const store = defineStore('user', {
    // 3-设置组件共享的状态,相当于组件的data
    state: () => ({
        userInfo: {
            name: '老刘',
            sex: '男',
            age: 17,
            isStudent: false
        },
        token: '5201314',
        password: '123456',
    }),
});

export default store;

src/App.vue

<!-- 这里不能用script setup,否则依然报错 -->
<script lang="ts">
import store from '@/store/user.ts';

export default {
    setup() {
        const userStore = store();

        function resetStore() {
            // 重置state
            userStore.$reset();
        }

        // 把响应式数据或方法return出去
        return {
            userStore,
            resetStore
        }
    },
}
</script>

重写一个$reset()方法(推荐)

原理:自定义pinia插件(Plugins),利用$patch() 重置整个state

在之前创建的pinia配置文件中修改(src/store/index.ts)。

import { createPinia } from 'pinia';
const pinia = createPinia();

// 1-使用pinia自定义插件
pinia.use(({ store }) => {
    // 2-获取最开始的State
    const initialState = JSON.parse(JSON.stringify(store.$state));
    // 3-重写$reset()方法
    store.$reset = () => {
        // 4-利用$patch()批量变更state,达到重置state的目的
        store.$patch(initialState);
    }
});

export default pinia;

推荐使用这种方法,这样就可以在script setup中愉快地使用pinia啦!

完整示例

仓库配置

src/store/index.ts

import { createPinia } from 'pinia';
const pinia = createPinia();

pinia.use(({ store }) => {
    const initialState = JSON.parse(JSON.stringify(store.$state));
    store.$reset = () => {
        store.$patch(initialState);
    }
});

export default pinia;

定义仓库

src/store/user.ts

// 组合式写法
import { defineStore } from "pinia";
import { ref, reactive, computed, watch } from 'vue';

const store = defineStore('user', () => {
    const userInfo = reactive({
        name: '老刘',
        sex: '男',
        age: 17,
        isStudent: false
    });
    const token = ref('5201314');
    const password = ref('123456');

    const name = computed(() => userInfo.name);
    const sex = computed(() => userInfo.sex);

    watch(() => userInfo.age, (val) => {
        console.log(val);
    });

    function addAge() {
        userInfo.age++;
    }

    return {
        userInfo,
        token,
        password,
        name,
        sex,
        addAge
    }
});

export default store;

父组件

src/App.vue

<template>
    <div>
        <button @click="resetStore">重置store</button>
        <h1>我是父组件</h1>
        <button @click="userStore.userInfo.age++">年龄+1</button>
        <span class="marginLeft60">姓名:{{ userStore.name }}</span>
        <span class="marginLeft60">性别:{{ userStore.sex }}</span>
        <span class="marginLeft60 red">年龄:{{ userStore.userInfo.age }}</span>
        <span class="marginLeft60 red">是否学生:{{ userStore.userInfo.isStudent ? '是' : '否' }}</span>
        <hr>

        <!-- 使用子组件A -->
        <son-a />
        <hr>

        <!-- 使用子组件B -->
        <son-b />
        <hr>
    </div>
</template>

<script setup lang="ts">
// 引入子组件
import SonA from './components/sonA.vue';
import SonB from './components/sonB.vue';

// 1-引入仓库
import store from '@/store/user.ts';

// 2-使用仓库
const userStore = store();

// 重置store
function resetStore() {
    userStore.$reset();
}
</script>

<style>
.marginLeft60 {
    margin-left: 60px;
}

.red {
    color: red;
}
</style>

子组件A

src/components/sonA.vue

<template>
    <div>
        <h2>我是子组件A</h2>
        <button @click="userStore.userInfo.isStudent = true">入学</button>
        <span class="marginLeft60">姓名:{{ userStore.name }}</span>
        <span class="marginLeft60">性别:{{ userStore.sex }}</span>
        <span class="marginLeft60 red">年龄:{{ userStore.userInfo.age }}</span>
        <span class="marginLeft60 red">是否学生:{{ userStore.userInfo.isStudent ? '是' : '否' }}</span>
        <grandson />
    </div>
</template>

<script setup lang="ts">
import Grandson from './grandson.vue';
import store from '@/store/user.ts';

const userStore = store();
</script>

子组件B

src/components/sonB.vue

<template>
    <div>
        <h2>我是子组件B</h2>
        <button @click="userStore.userInfo.isStudent = false">毕业</button>
        <span class="marginLeft60">姓名:{{ userStore.name }}</span>
        <span class="marginLeft60">性别:{{ userStore.sex }}</span>
        <span class="marginLeft60 red">年龄:{{ userStore.userInfo.age }}</span>
        <span class="marginLeft60 red">是否学生:{{ userStore.userInfo.isStudent ? '是' : '否' }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();
</script>

孙组件

src/components/grandson.vue

<template>
    <div>
        <h3>我是孙组件</h3>
        <span class="marginLeft60">姓名:{{ userStore.name }}</span>
        <span class="marginLeft60">性别:{{ userStore.sex }}</span>
        <span class="marginLeft60 red">年龄:{{ userStore.userInfo.age }}</span>
        <span class="marginLeft60 red">是否学生:{{ userStore.userInfo.isStudent ? '是' : '否' }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();
</script>

效果图

vue3探索——5分钟快速上手大菠萝pinia文章来源地址https://www.toymoban.com/news/detail-704254.html

到了这里,关于vue3探索——5分钟快速上手大菠萝pinia的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TypeScript快速上手语法+结合vue3用法

            前言:             本篇内容不涉及TypeScript安装以及配置,具体安装及配置篇可以看下面目录,本篇只涉及TypeScript语法相关内容,及结合vue3的用法。不讲废话,简单直接直接开撸。 目录      TypeScript的具体安装及配置  TypeScript快速上手语法+结合vue3用法 1、

    2024年02月03日
    浏览(36)
  • Pinia 快速上手要点

    使用 defineStore 创建一个 store, 每个 store 要设置一个唯一 id; 改变state 的值时不需要借助 mutation (pinia中没有mutation), 默认情况下,您可以通过 store 实例访问状态来直接读取和写入状态; 除了直接用 store.count++ 修改 store,你还可以调用 $patch 方法同时应用多个更改; $patch 方法也

    2024年02月11日
    浏览(42)
  • [GN] Vue3.2 快速上手 ---- 核心语法2

    用在普通 DOM 标签上,获取的是 DOM 节点。 用在组件标签上,获取的是组件实例对象。 用在普通 DOM 标签上: 用在组件标签上: 父组件App使用子组件Person Person组件标签上使用ref 可以获取组件实例 但需要子组件代码中 使用defineExpose暴露内容 App.vue是父组件,Person是子组件 父

    2024年01月21日
    浏览(57)
  • Vue3快速上手(七) ref和reactive对比

    表格形式更加直观吧: 项目 ref reactive 是否支持基本类型 支持 不支持 是否支持对象类型 支持 支持 对象类型是否支持属性直接赋值 不支持,需要.value 支持 是否支持直接重新分配对象 支持,因为操作的.value 不支持,需要使用object.assign()方法 是否支持基本类型 支持 不支持

    2024年02月19日
    浏览(43)
  • Vue3快速上手(八) toRefs和toRef的用法

    顾名思义,toRef 就是将其转换为ref的一种实现。详细请看: toRef就相当于是将对象Person里的某个属性,如name,单独解构赋值给name,并使得name同为响应式对象。且修改name的值时,person.name的值随之变化。 如下图可以看到: 1、name是一个ObjectRefImpl对象的实例。 2、底层还是个P

    2024年02月19日
    浏览(39)
  • 一分钟学会、三分钟上手、五分钟应用,快速上手责任链框架详解 | 京东云技术团队

    作者:京东物流 覃玉杰 责任链模式是开发过程中常用的一种设计模式,在SpringMVC、Netty等许多框架中均有实现。我们日常的开发中如果要使用责任链模式,通常需要自己来实现,但自己临时实现的责任链既不通用,也很容易产生框架与业务代码耦合不清的问题,增加Code Rev

    2024年02月03日
    浏览(43)
  • Vue--》探索Pinia:Vue状态管理的未来

    目录 Pinia的讲解与使用 Pinia的安装与使用 store数据操作 解构store数据

    2024年02月05日
    浏览(40)
  • 五分钟带你快速上手EFCore操作MySQL

    Entity Framework Core 是一个轻量级、跨平台的 ORM 框架,它允许 .NET 开发人员通过面向对象的方式访问数据库。EF Core 可以与各种关系型数据库进行交互,包括 SQL Server、MySQL、PostgreSQL 和 SQLite 等。 Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.Tools Pomelo.EntityFrameworkCore.MySql 注意版

    2024年04月17日
    浏览(35)
  • 【Linux】静态库和共享库一分钟快速上手

    程序库,对于程序原来说是非常重要的。但不少人对其不太了解,接下来一起学习其中的奥秘吧! 简单来说,程序库可以分为静态库和共享库。它们包含了数据和执行代码的文件。其不能单独执行,可以作为其他执行程序的一部分来完成某些功能。库的存在,可以使得程序模

    2024年02月08日
    浏览(36)
  • 前端开发小技巧 - 【Vue3 + TS】 - 在 TS + Vue3 中使用 Pinia,实现 Pinia 的持久化,优化Pinia(仓库统一管理)

    ts 中使用 pinia 和 Vue3 基本一致,唯一的不同点在于,需要根据接口文档给 state 标注类型,也要给 actions 标注类型; 以下都是 组合式API 的写法, 选项式API 的写法大家可以去官网看看; Pinia; 持久化插件 - pinia-plugin-persistedstate; 目标文件: src/types/user.d.ts (这里以 user.d.t

    2024年04月09日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包