vue使用pinia (vue2/vue3)
Posted 奥特曼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue使用pinia (vue2/vue3)相关的知识,希望对你有一定的参考价值。
pinia是什么?Pinia 是 Vue.js 的轻量级状态管理库
官方网站:Pinia
中文文档: 介绍 | Pinia 中文文档
pinia与vuex4
相同
- 是vue 官方 状态管理工具(作者是 Vue 核心团队成员)
- 是vue开发者工具支持pinia
不同
- pinia相比vuex4,对于vue3的 兼容性 更好
- pinia相比vuex4,具备完善的 类型推荐 => 对 TS 支持很友好
- Pinia 的 API 设计非常接近
Vuex 5
的提案。
- vuex只能有一个根级别的状态, pinia 直接就可以定义多个根级别状态
pinia核心概念
- state: 状态
- actions: 修改状态(包括同步和异步,pinia中没有mutations)
- getters: 计算属性
一、使用
1. 安装pinia vue2/vue3 通用
yarn add pinia
# 或者使用 npm
npm install pinia
2.如果是脚手架的创建的项目可以在安装,会自动创建一个出一个实例,帮助你快速引入pinia
vue add vue-cli-plugin-pinia
3.使用 pinia
store/index.js
import
defineStore
from 'pinia'
// 创建store,命名规则: useXxxxStore
// 参数1:store的唯一表示
// 参数2:对象,可以提供state actions getters
export const useCounterStore = defineStore('counter',
// data里中的数据
state: () => (
count: 1
),
// 计算属性
getters:
double: state => state.count * 2
,
// 相当于 vue中的 methods 既可以写同步代码也可以写异步
actions:
addCount ()
this.count++
)
vue2: Home.vue
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<div> pinia中的count值 count</div>
<div>pinia中的计算属性 double</div>
<button @click="addCount">count +1 </button>
<button @click="getCount">拿到count的值</button>
</div>
</template>
<script>
// @ is an alias to /src
import mapState, mapActions from 'pinia'
import useCounterStore from '@/store'
export default
name: 'Home',
computed:
...mapState(useCounterStore, ['count', 'double'])
,
methods:
...mapActions(useCounterStore, ['addCount']),
getCount ()
console.log(this.count)
</script>
vue3
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<div> pinia中的count值 store.count</div>
<div>pinia中的计算属性 store.double</div>
<button @click="addCount">count +1 </button>
<button @click="getCount">拿到count的值</button>
</div>
</template>
<script >
import useCounterStore from '@/store'
export default
setup ()
const store = useCounterStore()
const addCount = () =>
// 数据+1
store.count++
// 使用$patch 修改数据 好处是可以使用修改多个数据
// store.$patch(
// count: store.count + 1
// )
return store, addCount
</script>
二、持久化 vue3/vue2通用
持久化插件:Pinia Plugin Persist
安装命令
npm add pinia-plugin-persist
或
yarn add pinia-plugin-persist
vue2持久化
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import createPinia, PiniaVuePlugin from 'pinia'
import VueCompositionAPI from '@vue/composition-api'
// 引入持久化组件 若不想持久化 可不使用
import piniaPersist from 'pinia-plugin-persist'
const pinia = createPinia()
pinia.use(piniaPersist)
Vue.use(PiniaVuePlugin)
Vue.use(VueCompositionAPI)
Vue.config.productionTip = false
new Vue(
router,
pinia,
render: h => h(App)
).$mount('#app')
store/index.js
import
defineStore
from 'pinia'
export const useCounterStore = defineStore('counter',
// data里中的数据
state: () => (
count: 1
),
persist:
enabled: true, // 开启本地存储
strategies: [
key: 'counter1', // 修改当前存储的键名 若不修改则是上面的id
storage: localStorage // 修改当前的存储方式,如果不填 则存储方式为sessionstorage
]
)
vue3持久化
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import createPinia, PiniaVuePlugin from 'pinia'
import VueCompositionAPI from '@vue/composition-api'
// 引入持久化组件 若不想持久化 可不使用
import piniaPersist from 'pinia-plugin-persist'
const pinia = createPinia()
pinia.use(piniaPersist)
Vue.use(PiniaVuePlugin)
Vue.use(VueCompositionAPI)
Vue.config.productionTip = false
new Vue(
router,
pinia,
render: h => h(App)
).$mount('#app')
store/index.js
import
defineStore
from 'pinia'
export const useCounterStore = defineStore('counter',
// data里中的数据
state: () => (
count: 1
),
persist:
enabled: true, // 开启本地存储
strategies: [
key: 'counter1', // 修改当前存储的键名 若不修改则是上面的id
storage: localStorage // 修改当前的存储方式,如果不填 则存储方式为sessionstorage
]
)
三、storeToRefs
使用storeToRefs可以保证解构出来的数据也是响应式的。
在模板中使用数据时,要加上模块的名字,例如:
<template>
<div>
counter.count
</div>
</template>
<script setup>
import useCounterStore from '@/store'
const counter = useCounterStore()
</script>
如果我们想省略counter 第一个思路 解构
<script setup>
import useCounterStore from '@/store'
const counter = useCounterStore()
const count = counter
</script>
如果直接从pinia中结构,会丢失响应式
storeToRefs
可以保证解构出来的数据也是响应式的。
const state属性名1, state属性名2 = storeToRefs(模块名)
使用
<script setup>
import storeToRefs from 'pinia'
import useCounterStore from '@/store'
const counter = useCounterStore()
const count = storeToRefs(counter)
</script>
使用storeToRefs可以保证解构出来的数据也是响应式的
四、pinia模块化
src
├── store
│ ├── 模块1.js
│ └── 模块2.js
├── pages
│ ├── Home.vue
│ └── Login.vue
└── main.js
在某个.vue中使用模块时,先import useXXXStore from './模块', 然后 const xxx = useXXXStore(),来使用。如果在导入第二个模块就需要写两次
import useCounterStore from '@/store/counter'
import useCounterUser from '@/store/user'
const counter = useCounterStore()
const counter = useCounterUser()
改进
在复杂项目中,不可能把多个模块的数据都定义到一个store中,一般来说会一个模块对应一个store,最后通过一个根store进行整合
src
├── store
│ ├── modules
│ │ ├── user.js
│ │ └── counter.js
│ └── index.js // 根store
├── pages
│ └── 页面.vue
└── main.js
module/counter.js
import defineStore from 'pinia'
const useUserStore = defineStore('counter',
state: () => ( count: 1 ),
getters:
double: state => state.count * 2
,
actions:
addCount ()
this.count++
,
persist:
enabled: true
)
export default useUserStore
store/index.js
// 1. 分别导入各个模块
import useCounterStore from './module/counter'
import useUserStore from './module/user'
// 2. 统一导出useStore方法
export default function useStore ()
return
counter: useCounterStore(),
user: useUserStore()
store/user.js
import defineStore from 'pinia'
const useUserStore = defineStore('user',
state: () => ( name: '奥特曼', age: 18 ),
getters:
double: state => state.age * 2
,
actions:
editUserName ()
this.name = '迪迦'
,
persist:
enabled: true
)
export default useUserStore
注意: 每个文件中的 defineStore(id,) 中的id不要重复 否则在index.js 调用时以第一次调用为准
组件中使用
<template>
<div>
count name
<button @click="addCount">+1</button>
</div>
</template>
<script setup>
import storeToRefs from 'pinia'
// 导入工具函数
import useStore from '@/store'
// 解构一下
const counter, user = useStore()
// 使用storeToRefs可以保证解构出来的数据也是响应式的
const count = storeToRefs(counter)
const name = storeToRefs(user)
const addCount = counter
</script>
以上是关于vue使用pinia (vue2/vue3)的主要内容,如果未能解决你的问题,请参考以下文章