Pinia or Vuex?

2022-11-17  本文已影响0人  cyh_1

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

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

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

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

<script setup>
import storeUser from "@/store/user";
const store = storeUser();
store.count++
console.log(123, store);
</script>
<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。

上一篇下一篇

猜你喜欢

热点阅读