Pinia or Vuex?

Pinia是什么?

官网解释:

Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。

从官网的解释不难看出,Pinia和Vuex的作用是一样的,它也充当的是一个存储数据的作用,存储在Pinia的数据允许我们在各个组件中使用。

实际上,Pinia就是Vuex的升级版,官网也说过,为了尊重原作者,所以取名Pinia,而没有取名Vuex,所以可以将Pinia比作为Vue3的Vuex。

Pinia的使用

1. 安装pinia

npm install pinia

2. 引入pinia

vue3 中引入的使用

import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia);
app.mount('#app')

vue2 中引入的使用

import { createPinia } from 'pinia'
const pinia = createPinia()
new Vue({
  el: '#app',
  // 其他选项...
  // ...
  pinia,
})

3. Store

3.1 定义store

创建 store/user.js

import { defineStore } from 'pinia'
export const useStore = defineStore({
    id: 'user',
    state: () => ({
        count: 0,
        username: '10个肉包子'
    }),
    getters: {},
    actions: {},
})

3.2 使用store

<script setup>
import storeUser from "@/store/user";
const { counter } = storeUser();
console.log(123, count);
</script>

4. State

4.1 定义state

export default defineStore('user', {
    state: () => ({
        count: 0,
        username: '10个肉包子'
    }),
});

4.2 使用state

  • 方法 1. 直接获取

以 javascript 中的模块导出的方式导出 store 数据,state 中的数据均可通过变量.state 数据名获取

<script setup>
import storeUser from "@/store/user";
const { counter } = storeUser();
console.log(123, count);
</script>
  • 方法 2. 解构获取

store 是一个 reactive 响应式对象,直接解构会使其失去响应式,类似 setup 中的 props,为了既可解构又可保持其响应式,可使用 storeToRefs,它将为每个 reactive 属性创建 refs

<script setup>
import { storeToRefs } from "pinia";
import storeUser from "@/store/user";
const { count } = storeToRefs(storeUser());
console.log(123, count);
</script>
<template>
    <div>
        {{ count }}
    </div>
</template>

4.3 修改 state

  • 直接修改 state:
<script setup>
import storeUser from "@/store/user";
const store = storeUser();
store.count++
console.log(123, store);
</script>
  • $patch 已对象修改
<template>
  <div>index-{{store.count}}</div>
</template>
<script setup>
import storeUser from "@/store/user";
const store = storeUser();
store.$patch({
  count: 3,
});
</script>

缺点: 如果只需修改 state 数据中的某一项,仍然需要将整个对象传给 store。

或者

<template>
  <div>index-{{store.count}}</div>
</template>
<script setup>
import storeUser from "@/store/user";
const store = storeUser();
store.$patch({
  count: 3,
});
</script>

4.4 替换state

<template>
  <div>index-{{store.count}}</div>
</template>
<script setup>
import storeUser from "@/store/user"
const store = storeUser()
store.$state = { count: 666, username: 'Paimon' }
</script>

4.5 重置state

一键回复默认的 state 数据

<template>
  <div>index-{{store}}</div>
</template>

<script setup>
import storeUser from "@/store/user"
const store = storeUser()

store.$patch({
  count: 3,
});
setTimeout(() => {
  store.$reset()
}, 3000)
console.log(123, store)
</script>

5. Getters

5.1 获取数据

建议使用尖头函数

export const useStore = defineStore('user', {
  state: () => ({
    counter: 0,
  }),
  getters: {
    doubleCount: (state) => state.counter * 2,
  },
})
<template>
    <div> {{ doubleCount }} </div>
    <div> {{ counter }} </div>
</template>
<script setup>
import storeUser from "@/store/user"
import { storeToRefs } from 'pinia'
const store = storeUser();
const { doubleCount, counter } = storeToRefs(storeUser())
</script>

5.2 访问其他 getters

访问其他的 getter 需要使用 this, 注意:不能使用尖头函数了

export const useStore = defineStore('user', {
  state: () => ({
    counter: 0,
  }),
  getters: {
    doubleCount(state) {
      return state.counter * 2
    },
    doublePlusOne() {
      return this.doubleCount + 1
    },
  },
})

5.3 getters 传递参数

export const useStore = defineStore('user', {
  getters: {
    getUserById: (state) => {
      return (userId) => state.users.find((user) => user.id === userId)
    },
  },
})</pre>

<pre data-language="plain" id="tPS6e" class="ne-codeblock language-plain" style="border: 1px solid #e8e8e8; border-radius: 2px; background: #f9f9f9; padding: 16px; font-size: 13px; color: #595959"><template>
  <p>User 2: {{ store.getUserById(2) }}</p>
</template>
<script setup>
import storeUser from "../../store/user";
const store = storeUser();
</script>

注意: getters are not cached anymore 即 getters 不会被缓存,只能函数调用。

5.4 访问其他的 getter

即想要哪个 getters 则调用哪个 getter,因为 pinia 没有总入口,和 vuex 有本质区别。

import { useOtherStore } from './other-store'

export const useStore = defineStore('main', {
  state: () => ({
    // ...
  }),
  getters: {
    otherGetter(state) {
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})

5.5 使用 mapState 访问 store 中的数据

import { mapState } from 'pinia'
import storeUser from "@/store/user";

export default {
  computed: {
    ...mapState(storeUser, ['doubleCount'])
    ...mapState(storeUser, {
      myOwnName: 'doubleCounter',
      double: state => state.doubleCount,
    }),
  },
}

6. Actions

6.1 获取方法

export const useStore = defineStore('user', {
  state: () => ({
    count: 0,
  }),
  actions: {
    increment() {
      this.count++
    },
    randomizeCounter() {
      this.count = Math.round(100 * Math.random())
    },
  },
})

6.2 使用方法

  • 同步的方式
<script setup>
import storeUser from "@/store/user"
const store = storeUser()
</script>
<template>
    <button @click="store.increment()">增加</button>
</template>
  • 异步的方式
import { mande } from 'mande'
const api = '@/api/users'
export const useUsers = defineStore('users', {
  state: () => ({
    userData: {},
  }),

  actions: {
    async registerUser(login, password) {
      try {
        this.userData = await api.post({ login, password })
        console.info(`Welcome back ${this.userData.name}!`)
      } catch (error) {
         console.error(error)
        return error
      }
    },
  },
})

Pinia 数据持久化插件

1. 安装

npm i pinia-plugin-persist

2. 引入

Vue2中引入使用

import Vue from 'vue'
import vueCompositionApi from '@vue/composition-api'
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persist'
import App from './App.vue'

const pinia = createPinia()
pinia.use(piniaPersist)

Vue.use(vueCompositionApi)
Vue.use(pinia)

new Vue({
  pinia,
  render: h => h(App),
}).$mount('#app')

Vue3中引入使用

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persist'

const pinia = createPinia()
pinia.use(piniaPersist)

createApp({})
  .use(pinia)
  .mount('#app')

Pinia持久化插件用法

pinia的优点

  1. Vue2和Vue3都支持,这让我们同时使用Vue2和Vue3的小伙伴都能很快上手。

  2. Pinia中只有state、getter、action,抛弃了Vuex中的Mutation,pinia直接抛弃它了,这无疑减少了我们工作量。

  3. Pinia中action支持同步和异步,Vuex不支持

  4. 良好的Typescript支持,Vue3都推荐使用TS来编写,这个时候使用Pinia就非常合适了

  5. 无需再创建各个模块嵌套了,Vuex中如果数据过多,我们通常分模块来进行管理,稍显麻烦,而pinia中每个store都是独立的,互相不影响。
    image
  6. 体积非常小,只有1KB左右。

  7. pinia支持插件来扩展自身功能。

  8. 支持服务端渲染。

Pinia 与 Vuex对比

Pinia:State、Gettes、Actions(同步异步都支持)

Pinia图解:


image

Vuex:State、Gettes、Mutations(同步)、Actions(异步)

Vuex图解:


image

Pinia 当前最新版是 2.x,即支持 Vue2 也支持 Vue3;Vuex 当前最新版是 4.x,Vuex4 用于 Vue3,Vuex3 用于 Vue2。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,176评论 5 469
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,190评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,232评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,953评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,879评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,177评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,626评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,295评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,436评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,365评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,414评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,096评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,685评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,771评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,987评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,438评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,032评论 2 341

推荐阅读更多精彩内容