pinia的使用

一、初始化配置

1.创建项目

使用 NPM:

$ npm create vite@latest 

使用 Yarn:

$ yarn create vite 

使用 PNPM:

$ yarn create vite 

2.安装 Pinia

使用你喜欢的包管理器安装pinia

yarn add pinia
# or with npm
npm install pinia

二、基本使用

1.创建 Pinia 实例并挂载

src/main.js

import { createApp } from 'vue';
import './style.css';
import App from './App.vue';
import { createPinia } from 'pinia';
​
// 创建 Pinia 实例
const pinia = createPinia();
​
// 挂载到Vue根实例
createApp(App).use(pinia).mount('#app');

如果使用的是Vue2,还需要安装一个插件,并将创建一个pinia注入到应用的root:

import { createPinia, PiniaVuePlugin } from 'pinia'
​
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
​
new Vue({
  el: '#app',
  // 其他选项...
  // ...
  // 注意同一个pinia实例可以在多个Vue应用中使用
  pinia,
})

2.定义 Store

store 是使用defineStore() 定义的,第一个参数是整个应用中store的唯一名称(id) 建议: 可以为defineStore()的返回值任意命名,但是最好使用use加上store的名称和Store,例如:useUserStore、useCartStore、useProductStore

1.在src目录下,创建store目录,创建user.ts 在里面写入

import { defineStore } from 'pinia'
​
export const useStore = defineStore('main', {
  // 具体代码...
})

3.Store中的选项

类似于Vue的选项API,也可以传递一个带有state、actions和getters属性的选项对象

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0, name: 'Eduardo' }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

然而,state就类似于组件的 data ,用来存储全局状态的,getters就类似于组件的 computed,用来封装计算属性,有缓存功能,actions类似于组件的 methods,用来封装业务逻辑,修改 state。

4.基本使用

如果你要在组件中使用,就需要先将store引入进来,并在setup()中声明调用

import { useMainStore } from '../store';
​
export default ({
  setup(){
    const mainStore = useMainStore();
    console.log(mainStore.count); // 这样就可以在组件中获取到Store中的count了
  },
})

接下来就是在模板中使用了,想必不用说都能猜出来怎么写 那么,这样就会产生一个问题,每次都需要mainStore,这样就很麻烦。

import { useMainStore } from '../store';
​
export default ({
  setup(){
    const mainStore = useMainStore();
    console.log(mainStore.count); // 这样就可以在组件中获取到Store中的count了
  },
})

问题来了怎么解决?如果你对ES6了解的话可能会想到解构出来。但是这样取出来的数据是有问题的,它已经丢失了响应式,也就是一次性的。

// Pinia 其实就是把 state 数据都做了 reactive 处理了
const { count, foo } = mainStore;

就像上面这段代码,解构出来的数据就已经失去了响应式,如果之后对数据的修改Vue是无法监测到数据变化的。 解决办法:这里就需要使用Pinia为我们提供的storeToRefs()API这就类似Vue3中的toRefs()

import { storeToRefs } from 'pinia'
​
export default ({
  setup(){
    const mainStore = useMainStore();
        const { count, foo } = storeToRefs(mainStore);
​
    return {
      count,
      foo,
    }
  },
})

5.状态更新和Actions

Actions相当于组件中的方法。它们可以使用defineStore()中的actions属性来定义,并且它们非常适合定义业务逻辑 那么接下来怎么修改数据呢?这里有四种方法来修改。 例如:这里我们需要修改state中的count、foo、arr

import { defineStore } from 'pinia';
​
export const useMainStore = defineStore('main', {
  state: () => ({
    count: 100,
    foo: 'bar',
    arr: [1, 2, 3],
  }),
  ...
}
<template>
    <p>{{ count }}</p>
    <p>{{ foo }}</p>
    <p>{{ arr }}</p>
    <hr />
    <p>
        <button @click="handleChangeState">修改数据</button>
    </p>
</template>
​
<script setup>
    ...
  const handleChangeState = () =>{
    ...
  }
</script>

方法一:最简单的方式修改

mainStore.count++;
mainStore.foo = 'hello';

方法二:如果需要修改多个数据,建议使用 $patch批量更新

mainStore.$patch({
  count: mainStore.count + 1,
  foo: 'hello',
  // 由于是以对象形式传递的,显然如果要给数组追加元素不是一个很好的选择
  arr: [...mainStore.arr, 4],
});

方法三:更好的批量更新的方法:$patch也可以传递一个函数

mainStore.$patch((state) => {
  // 这里接收的形参就是state
  state.count++;
  state.foo = 'hello';
  state.arr.push(4);
});

方法四:逻辑比较多的时候可以封装到 actions 里面

mainStore.changeState(); // 在修改数据的方法中可以直接调用这个封装在actions里面的函数
import { defineStore } from 'pinia';
​
export const useMainStore = defineStore('main', {
  ...
  actions: {
    // 注意:不能使用箭头函数定义,因为使用箭头函数会导致 this 指向错误
    changeState(num) {
      this.count += num;
      this.foo = 'hello';
      this.arr.push(4);
​
      // this.$patch({}) // 这里如果批量更新和方法二、三一样
      // this.$patch((state) => {});
    },
  },
}

6.Getters使用

Getters完全等同于Store state的计算值。可以使用defineStore()中的getters属性来定义它们,并且它们将state作为第一个参数接收,以鼓励使用箭头函数。如果你使用的是普通函数的话,这个参数是可选的不接收也可以使用this,

export const useMainStore = defineStore('main', {
  state: () => ({
    count: 100,
  }),
  getters: {
    // 函数接收一个可选的参数,是 state 对象
    /* count10(state) {
            console.log('count10 被调用了');
            return state.count * 10;
        }, */
​
    // 🔴 如果是在ts中的话,this的类型是推导不出来的,所以需要手动指定
    /* count10() {
            console.log('count10 被调用了');
            return this.count * 10;
        }, */
    count10: (state) => state.count * 10,
  },
},

src/store/index.js

import { defineStore } from 'pinia';
​
// 1、定义容器
// 参数1:容器名称 ID ,必须唯一,将来 Pinia 会把所有的容器挂载到根容器
// 参数2:选项对象
// 返回值:一个函数,调用得到容器实例
export const useMainStore = defineStore('main', {
    /**
     * 类似于组件的 data,用来存储全局状态的
     * 1、必须是函数:这样是为了在服务端渲染的时候避免交叉请求导致数据的状态污染
     * 2、必须是箭头函数:这是为了更好的 TS 类型推导
     */
    state: () => ({
        count: 100,
        foo: 'bar',
        arr: [1, 2, 3],
    }),
    /**
     * 类似于组件的 computed,用来封装计算属性,有缓存功能
     */
    getters: {
        // 函数接收一个可选的参数,是 state 对象
        /* count10(state) {
            console.log('count10 被调用了');
            return state.count * 10;
        }, */
​
        // 🔴 如果是在ts中的话,this的类型是推导不出来的,所以需要手动指定
        /* count10() {
            console.log('count10 被调用了');
            return this.count * 10;
        }, */
        count10: (state) => state.count * 10,
    },
​
    /**
     * 类似于组件的 methods,用来封装业务逻辑,修改 state
     */
    actions: {
        // 🔴 注意:不能使用箭头函数定义,因为使用箭头函数会导致 this 指向错误
        changeState(num) {
            this.count += num;
            this.foo = 'hello';
            this.arr.push(4);
​
            // this.$patch({})
            // this.$patch((state) => {});
        },
    },
});
// 2、使用容器中的 state
​
// 3、修改 state
​
// 4、容器中的 action 的使用

src/components/HelloWord.vue

<template>
  <p>{{ mainStore.count }}</p>
  <p>{{ mainStore.foo }}</p>
  <p>{{ mainStore.arr }}</p>
  <p>{{ mainStore.count10 }}</p>
  <p>{{ mainStore.count10 }}</p>
  <p>{{ mainStore.count10 }}</p>
​
  <hr />
​
  <p>{{ count }}</p>
  <p>{{ foo }}</p>
​
  <hr />
​
  <p>
    <button @click="handleChangeState">修改数据</button>
  </p>
</template>
​
<script setup>
  import { storeToRefs } from 'pinia';
  import { useMainStore } from '../store';
​
  const mainStore = useMainStore();
​
  console.log(mainStore.count);
​
  // 这是有问题的,因为这样拿到的数据不是响应式的,是一次性的
  // Pinia 其实就是把 state 数据都做了 reactive 处理了
  // const { count, foo } = mainStore;
​
  // 解决办法就是使用 storeToRefs
  // 把解构出来的数据做 ref 响应式代理
  const { count, foo } = storeToRefs(mainStore);
​
  const handleChangeState = () => {
    // 方法一:最简单的方式就是这样
    // mainStore.count++;
    // mainStore.foo = 'hello';
​
    // 方法二:如果需要修改多个数据,建议使用 $patch 批量更新
    /* mainStore.$patch({
        count: mainStore.count + 1,
        foo: 'hello',
        arr: [...mainStore.arr, 4],
    }); */
​
    // 方法三 更好的批量更新的方法:$patch 也可以传入一个函数
    /* mainStore.$patch((state) => {
        state.count++;
        state.foo = 'hello';
        state.arr.push(4);
    }); */
​
    // 方法四:逻辑比较多的时候可以封装到 actions 里面
    mainStore.changeState(10);
  };
</script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值