Pinia是什么
Pinia
是 Vue
的存储库,允许您跨组件/页面共享状态。Pinia
这款产品最初是为了探索 Vuex
的下一个版本,整合了核心团队关于 Vuex 5
的许多想法。最终,我们意识到 Pinia
已经实现了我们想要在 Vuex 5
中提供的大部分内容,因此决定将其作为 新的官方推荐
。
Pinia特点
- 足够轻量,Pinia 重约
1kb
,甚至会忘记它的存在! - 去除
Mutation
,Actions
支持同步和异步(Actions
一个顶俩,写起来简洁); - 无需手动注册
Store
,Store 仅需要时才自动注册。如果从不使用,则永远不会“注册”(省心); - 没有模块嵌套,只有
Store
的概念,Store 之间可以自由使用,更好的代码分割; Vue2
和Vue3
都能支持;- 支持大型项目迁移期间,
Pinia
和Vuex
混合使用(贴心迁移); - 更完美的
typescript
的支持; - 与
Vue devtools
挂钩,Vue2 和 Vue3 开发体验更好; - 支持插件扩展功能;
- 支持模块热更新,无需加载页面可以修改容器,可以保持任何现有的状态;
- 支持服务端渲染;
Vuex
与 Pinia
用哪个
Vuex
现在处于维护模式。它仍然可以工作,但不再添加新的功能。对于新的应用项目
,建议使用 Pinia
。Pinia
已经实现了我们想要在 Vuex 5
中提供的大部分内容,因此决定将其作为 新的官方推荐(注意:旧版网站没有更新)
如何使用 Pinia
一、安装
npm install pinia
二、定义 Store
新建 src/stores 目录并在其下面创建 index.ts
Pinia
的目录通常被称为 stores 而不是store
, 这是为了强调Pinia
使用多个store
,而不是Vuex
中的单个store
,同时也有迁移期间Pinia
和Vuex
混合使用的考虑。
// src/stores/index.ts
// 引入Store定义函数
import { defineStore } from 'pinia'
// 定义Store实例并导出,useStore可以是任何东西,比如useUser, useCart
// 第一个参数,唯一不可重复,字符串类型,作为仓库ID 以区分仓库
// 第二个参数,以对象形式配置仓库的state,getters,actions
export const useStore = defineStore('main', {
// state 推荐箭头函数,为了TS类型推断
state: () => {
return {
name: '张三',
counter: 0
}
},
getters: {},
actions: {}
})
在 main.ts 中引入并挂载到根实例
// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
// 创建Vue应用实例
// 实例化 Pinia
// 以插件形式挂载Pinia实例
createApp(App).use(createPinia()).mount('#app')
三、State
1、访问State
{{store.name}}
{{name}}
{{counter}}
2、修改State
1、单个参数修改 state
store.counter++
2、多个参数修改 state
store.$patch({
counter: store.counter + 1,
name: 'Abalam',
})
3、全部修改 state
store.$state = { counter: 666, name: 'Paimon' }
或
pinia.state.value = {}
3、重置State
将状态重置为初始值
const store = useStore()
store.$reset()
4、vue2写法
import { mapState } from 'pinia'
import { useCounterStore } from '../stores/counterStore'
export default {
computed: {
...mapState(useCounterStore, ['counter'])
// 或
...mapState(useCounterStore, {
myOwnName: 'counter',
double: store => store.counter * 2,
magicValue(store) {
return store.someGetter + this.counter + this.double
},
}),
},
}
四、Getters
getter
中的值有缓存特性,类似于computed,如果值没有改变,多次使用也只会调用一次
1、定义Getters
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2,
// 自动推导返回类型
doubleCount(state) {
return state.counter * 2
},
// 依赖getters返回参数,则需要显性的设置返回类型
doublePlusOne(): number {
return this.doubleCount + 1
},
},
})
2、使用Getters
Double count is {{ store.doubleCount }}
3、vue2写法
import { mapState } from 'pinia'
import { useCounterStore } from '../stores/counterStore'
export default {
computed: {
...mapState(useCounterStore, ['doubleCount'])
// 或
...mapState(useCounterStore, {
myOwnName: 'doubleCounter',
double: store => store.doubleCount,
}),
},
}
五、Actions
Pinia
中删除了 Mutation
,Actions
支持同步和异步
1、定义 Actions
// 同步
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
userData: null,
}),
actions: {
increment() {
this.counter++
},
randomizeCounter() {
this.counter = Math.round(100 * Math.random())
},
},
})
// 异步
import { mande } from 'mande'
const api = mande('/api/users')
export const useUsers = defineStore('users', {
state: () => ({
userData: null,
}),
actions: {
async registerUser(login, password) {
this.userData = await api.post({ login, password })
},
},
})
2、调用 Actions
1、可以直接调用 store
的任何方法
2、action
间的相互调用,直接用 this
访问即可。
export const useUserStore = defineStore({'user',
actions: {
increment() {
this.counter++
},
increase() {
// 调用另一个 action 的方法
this.increment()
},
}
})
3、在 action
里调用其他 store
里的 action
也比较简单,引入对应的 store
后即可访问其内部的方法。
import { useAuthStore } from './auth-store'
export const useSettingsStore = defineStore('settings', {
state: () => ({
preferences: null,
}),
actions: {
async fetchUserPreferences() {
// 调用 auth-store store 里的 action 方法
const auth = useAuthStore()
if (auth.isAuthenticated) {
this.preferences = await fetchPreferences()
} else {
throw new Error('User must be authenticated')
}
},
},
})
3、vue2写法
import { mapActions } from 'pinia'
import { useCounterStore } from '../stores/counterStore'
export default {
methods: {
...mapActions(useCounterStore, ['increment'])
// 或
...mapActions(useCounterStore, { myOwnName: 'doubleCounter' }),
},
}
总结
总得来说,Pinia
就是 Vuex
的官方替代版,可以更好的支持 Vue2,Vue3
以及TypeScript
。在 Vuex
的基础上去掉了 Mutation
、模块嵌套
等概念,语法更简洁直接, 更符合 Vue3
的 Composition api,为 TypeScript
提供了更好的类型推导。以上是 Pinia.js 用法的一些介绍,Pinia.js 的内容还远不止这些,更多内容及使用有待大家自己探索。Pinia文档