Vue - pinia
Pinia 是 Vue 3 的官方状态管理库,旨在替代 Vuex,提供更简单的 API 和更好的 TypeScript 支持。Pinia 的设计遵循了组合式 API 的理念,能够很好地与 Vue 3 的功能结合使用。
Pinia 的基本概念
- Store: Pinia 中的核心概念,类似于 Vuex 中的 Store。它是一个用于管理状态的中心地点。
- State: 存储的数据,可以在多个组件之间共享。
- Getters: 类似于计算属性,用于从状态派生出新的信息。
- Actions: 用于包含逻辑的方法,可以用于修改状态或处理异步操作。
步骤一:下载 pinia :
npm install pinia
// 或者
pnpm install pinia
步骤二:设置 pinia :
步骤三:创建 store 文件夹
// person.ts 船舰一个新的 store
import { defineStore } from "pinia";
export const usePersonStore = defineStore('person', {
// 真正存储数据的地方
state() {
return {
sum:20
}
}
})
import axios from "axios";
import { nanoid } from "nanoid";
import { defineStore } from "pinia";
export const useTalkStore = defineStore('talk', {
actions: {
async getATalk() {
// 发送请求
const res = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
// 把请求回来的字符串,包装成一个对象
// pnpm i nanoid 自动生成id
const obj = { id: nanoid(), title: res.data.content }
// 放入数组当中
this.talkList.unshift(obj);
}
},
// 真正存储数据的地方
state() {
return {
talkList: [
{ id: '001', title: '星期一' },
{ id: '002', title: '星期二' },
{ id: '003', title: '星期三' },
]
}
}
})
步骤四:使用 store (存储和读取数据)
// Person.vue 使用 pinia 前
<template>
<div class="person">
<h2>当前求和为:{
{sum}}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="changeSum1">加</button>
<button @click="changeSum2">减</button>
</div>
</template>
<script setup lang='ts' >
import { ref } from 'vue'
const sum = ref(1);
// 选择的数字
const n = ref(1);
const changeSum1 = ()=>{
sum.value += n.value;
}
const changeSum2 = ()=>{
sum.value -= n.value;
}
</script>
<style scoped>
</style>
// Person.vue 使用 pinia 后
<template>
<div class="person">
<h2>当前求和为:{
{personStore.sum}}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="changeSum1">加</button>
<button @click="changeSum2">减</button>
</div>
</template>
<script setup lang='ts' >
import { ref } from 'vue'
import { usePersonStore } from '../store/person'
const personStore = usePersonStore();
// 以下两种方式都可以拿到state中的数据
// console.log('@',personStore.sum);
// console.log('@@@',personStore.$state.sum);
// 选择的数字
const n = ref(1);
// const changeSum1 = ()=>{
// }
// const changeSum2 = ()=>{
// }
</script>
<style scoped>
</style>
// Talk.vue 使用 pinia 前
<template>
<div class="talk">
<button @click="getTalk">获取一句话</button>
<ul>
<li v-for="talk in talkList" :key="talk.id">
{
{talk.title}}
</li>
</ul>
</div>
</template>
<script setup lang='ts'>
import axios from 'axios';
import { nanoid } from 'nanoid';
import { reactive } from 'vue';
const talkList = reactive([
{ id: '001', title: '星期一' },
{ id: '002', title: '星期二' },
{ id: '003', title: '星期三' },
]);
const getTalk = async () => {
// 简单写法:连续解构赋值 + 重命名
// const {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand/qinghua?format=json')
// const obj = { id: nanoid(), title };
// 发送请求
const res = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
// 把请求回来的字符串,包装成一个对象
// pnpm i nanoid 自动生成id
const obj = { id: nanoid(), title: res.data.content }
// 放入数组当中
talkList.unshift(obj);
}
</script>
<style>
</style>
<template>
<div class="talk">
<button @click="getTalk">获取一句话</button>
<ul>
<li v-for="talk in talkStore.talkList" :key="talk.id">
{
{talk.title}}
</li>
</ul>
</div>
</template>
<script setup lang='ts'>
import { useTalkStore } from '../store/talk';
// import { storeToRefs } from 'pinia';
const talkStore = useTalkStore();
// const { talkList } = storeToRefs(talkStore)
// 与 watch 类似
talkStore.$subscribe((mutate,state) => {
console.log('talkStore 里面保存的数据发生了变化',mutate,state);
})
const getTalk=() => {
talkStore.getATalk();
}
</script>
<style>
</style>
步骤五:修改数据(三种方式)
// person.ts
import { defineStore } from "pinia";
export const usePersonStore = defineStore('person', {
// 真正存储数据的地方
state() {
return {
sum: 20,
name: '8520',
age:20
}
},
// actions 里面放的是一个个方法,用于响应组件中的“动作”
actions:{
increment(value){
console.log('increment 被调用了', value);
// 修改数据(this 是当前的 store)
this.sum += value;
}
},
getters: {
// 可以对数据进行加工
bigSum(state) {
return state.sum * 10;
},
// 也可以被解构 调用
}
})
<template>
<div class="person">
<h2>当前求和为:{
{personStore.sum}}</h2>
<h2>姓名:{
{personStore.name}},年龄:{
{personStore.age}}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="changeSum1">加</button>
<button @click="changeSum2">减</button>
</div>
</template>
<script setup lang='ts' >
import { ref } from 'vue'
// 引入 usePersonStore
import { usePersonStore } from '../store/person'
import { storeToRefs } from 'pinia';
// 使用 usePersonStore ,得到一个专门保存 person 相关的 store
const personStore = usePersonStore();
// storeToRefs 只会关注 store 中的数据,不会对方法进行 ref 包裹
const { sum, name, age, bigSum } = storeToRefs(personStore)
// 选择的数字
const n = ref(1);
// 加
const changeSum1 = () => {
// 第一种修改方式
// personStore.sum += n.value;
// 第二种修改方式 批量修改
// personStore.$patch({
// sum: 858,
// name: '5632',
// age:55
// })
// 第三种修改方式 利用 actions
personStore.increment(n.value)
}
// 减
const changeSum2 = () => {
personStore.sum -= n.value;
}
</script>