Pinia,vuejs的官方状态库,由vuejs团队成员 eduardo san moartin 开发的一个新的状态管理工具,我来为大家讲解一下关于popping怎么自学?跟着小编一起来看一看吧!
popping怎么自学
Pinia,一个更简洁的 vuejs 状态管理工具Pinia,vuejs的官方状态库,由vuejs团队成员 eduardo san moartin 开发的一个新的状态管理工具。
实际上 Pinia 就是 Vuex5.0。
pinia 同时支持 vue2 和 vue3,下文以 vue3 为例。
安装和配置
yarn add pinia@next
# or
npm install pinia@next
在工程的入口文件配置 pinia
// main.js
import { createPinia } from 'pinia
// ...
createApp(App).use(createPinia()).mount('#app')
现在,准备工作已经就绪。
定义 Storepinia 和 vuex 的定义方式不太一样。在 vuex 中,虽然可以拆分不同的module,但是整个应用程序只有一个主要的store对象。而pinia是开箱即用的模块化设计,没有像vuex那样的单一store对象,而是给每个store设置唯一的命名空间。下面,让我们来试试创建一个【登录用户】的store对象。
import { defineStore } from 'pinia
export const useLoggedInUserSotre = defineStore({
// id 是必需的,类似 vuex 中为每个module设置namespaced,该id名称会显示在vue devtools中
id: 'loggedInUser',
State: () => ({}),
getters: {},
actions: {}
})
接下来,在组件中使用这个 store。
<script>
import { useLoggedInUserStore } from '@/store/loggedInUser'
export default {
setup() {
const user = useLoggedInUserStore()
}
}
</script>
这和 vuex 的使用方式有很大的不同,vuex 通过其api,将store和组件进行连接,而pinia,是以es module的方式import到组件内,这让我们更加清楚store来自那里,可读性更高。
State配置好store后,我们就可以定义状态了,在pinia中定义state数据很简单,和我们在组件中定义data数据的方式类似。pinia中的state是一个函数,该函数返回一个包括不同类型数据的对象。这和vue组件中的data函数非常相似,唯一的却别就是函数的名称不同:state vs data。
// store/loggedInUser.js
state: ()=>({ name: 'John Doe', email: 'fake@email.com', username: 'jd123'})
在组件中访问state时,只需要访问创建的user对象的属性即可,无需再像vuex那样,要先在 computed 中的使用扩展运算符处理state,还得通过state.namespaced.xxx的方式来访问状态,pinia的使用方式对开发者来说,非常友好。
<template>
<h1> hello, {{user.name}}</h1>
</template>
<script>
import { useLoggedInUserStore } from '@/store/loggedInUser'
export default {
setup() {
const user = useLoggedInUserStore()
const name = user.name
return {
user,
name
}
}
}
</script>
我们在使用 vuex 时,会将 store 用 computed 处理,使数据具有响应式属性,当 store 数据变化的,组件内对 store 的引用才会有相应的变化。那么对于 pinia 来说也是一样的。不管是 state 还是 getters 都需要 computed 来监听变化。
<template>
<h1> hello, {{user.name}}</h1>
</template>
<script>
import { computed } from 'vue'
import { useLoggedInUserStore } from '@/store/loggedInUser'
export default {
setup() {
const user = useLoggedInUserStore()
// 使用 computed 让数据具有响应式
const name = computed(() => user.name)
return {
user,
name
}
}
}
</script>
需要注意的是,在使用store时,如果进行了解构,这将会使属性失去其响应式。
// 解构后,属性不再具有响应式
const { name, email } = useLoggedInUserStore()
最后,如果使用options API(在vue3中,这应该是比较少见的情况),你可以通过mapState来使用store,但这和vuex也有一些不同,第一个参数为要获取的store,第二个参数为要获取的state属性。
//AppComponent.vue
<template>
<h1>Hello, my name is {{name}}</h1>
</template>
<script>
import {mapState} from 'pinia'
import { useLoggedInUserStore } from '@/store/loggedInUser
export default{
computed:{
...mapState(useLoggedInUserStore, ['name'])
}
}
</script>
Pinia 中的 getter 与 vuex 中的 getter 、组件中的 computed 属性具有相同的用途。 在 getter 中可以通过2种方式来访问state。
第一种方式是通过 this 关键字,在函数声明或者对象的方法属性中都可以通过 this 正常访问到 state,但是,不能使用箭头函数,因为箭头函数没有自己的 this 。
import { defineStore } from 'pinia'
export const usePostsStore = defineStore({
id: 'PostsStore',
state: () => ({ posts: ['post1', 'post2'] }),
getters: {
postsCount: function () {
return this.posts.length
},
// 方法的简洁表示法
postsCount () {
return this.posts.length
},
// 错误:不能使用箭头函数
postsCount: () => this.posts.length
}
})
第二种方式是通过getter 方法中的 state 参数来访问状态,在这种方式下,可以在getter中使用箭头函数。
import { defineStore } from 'pinia'
export const usePostsStore = defineStore({
//...
getters:{
// 箭头函数
postsCount: state => state.posts.length,
}
})
此外,getters属性直接的互相访问,可以使用 this ,但同样不能用箭头函数。
import { defineStore } from 'pinia'
export const usePostsStore = defineStore({
//...
getters:{
postsCount: state => state.posts.length,
// 通过 this 访问到其他的 getters 方法,但不能使用箭头函数
postsCountMessage(){ return `${this.postsCount} posts available` }
}
})
在组件中访问getters时,和访问state状态一样,无需再通过额外的getters对象。
<template>
<p>{{postsCount}} posts available</p>
</template>
<script>
import { usePostsStore } from "@/store/PostsStore";
export default {
setup() {
const PostsStore = usePostsStore();
return { postsCount: PostsStore.postsCount };
}
};
</script>
同样的,如果使用options API,可以通过computed来访问。
<template>
<p>{{postsCount}} posts available</p>
</template>
<script>
import { mapState } from 'pinia'
import { usePostsStore } from "@/store/PostsStore";
export default {
computed:{
...mapState(usePostsStore, ['postsCount'])
}
};
</script>
和 vuex 不同,pinia 仅能通过 actions 来改变状态,没有 mutations。
下面来看看关于actions的一些特性和最佳实践:
- 可以在组件中直接调用
- actions 之间可以互相调用
- 可以直接在 store 实例上调用(不需要 dispatch 方法)
- 可以是异步或同步方法
- 可以有任意数量的参数
- 可以在actions中更改state
- 可以通过this访问属性名来更改state属性,或者使用$patch批量更改state属性。
import { defineStore } from 'pinia'
export const usePostsStore = defineStore({
id: 'PostsStore',
state: ()=>({
posts: ['post 1', 'post 2', 'post 3', 'post 4'],
user: { postsCount: 2 },
errors: []
}),
getters:{
postsCount: state => state.posts.length,
},
actions:{
async insertPost(post){
try {
await doAjaxRequest(post)
// 修改多个 state 状态
this.posts.push(post)
this.user.postsCount
// 或者使用 $patch
this.$patch((state) => {
state.posts.push(post)
state.user.postsCount
})
}catch(error){
this.errors.push(error)
}
}
}
})
定义 actions 后,在组件中可以像state 或者 getter 一样,直接访问到 actions。
<template>
<input type="text" v-model="post" />
<button @click="insertPost(post)">Save</button>
</template>
<script>
import { usePostsStore } from '@/store/PostsStore';
export default{
data(){
return { post: '' }
},
setup(){
const PostsStore = usePostsStore()
return { insertPost: PostsStore.insertPost }
},
}
</script>
如果使用 options API,需要通过 mapActions 来访问actions。
<template>
<input type="text" v-model="post" />
<button @click="insertPost(post)">Save</button>
</template>
<script>
import {mapActions} from 'pinia'
import { usePostsStore } from '@/store/PostsStore';
export default{
data(){
return { post: '' }
},
methods:{
...mapActions(usePostsStore, ['insertPost'])
}
}
</script>
pinia 本身是模块化,不需要像 vuex 那样拆分模块后再组合在一起,在创建一个store module的时候,就可以直接在组件中引用,也不需要挂载在 vue 实例上。
模块之间如何互相访问呢?这和在组件中使用类似。
store/posts.js
import { defineStore } from 'pinia'
export const usePostsStore = defineStore({
id: 'PostsStore',
state: ()=>({
posts: ['post 1', 'post 2', 'post 3', 'post 4'],
user: { postsCount: 2 },
errors: []
}),
getters:{
// 通过 this 访问到其他的 getters 方法,但不能使用箭头函数
postsCountMessage(){ return `${this.postsCount} posts available` }
}
})
store/loggedInUser.js
在 loggedInUser 中访问 posts store。
import { defineStore } from 'pinia
// 在 loggedInUser 中引入 posts
import { usePostsStore } from './posts'
export const useLoggedInUserSotre = defineStore({
id: 'loggedInUser',
state: () => ({}),
getters: {},
actions: {
add () {
// 在 actions 中访问其他 store,在 getters 中类似
// 创建 store 实例
const PostsStore = usePostsStore()
// 打印出 posts 的长度
console.log(PostsStore.posts.length)
},
})
我们时常需要在 devtools 中调试状态,在 vue2 中,可以在 devtools 的 vuex 面板查看到 pinia 的状态。
而在 vue3 中,安装新版 devtools后,可以切换到pinia面板查看状态,但目前还不支持时间旅行功能(还未看到官方消息,有看到官方公布的,可以贴个链接)。
总结让我们来快速回顾一下 Pinia 的特性,以帮助你更好的选择项目的状态管理工具。
- 由 vuejs 团队核心成员开发和维护
- 使用上更接近 es module 的方式
- 不需要额外的 mutations
- 集成 vue devtools
- Vue3 官方文档中后续的状态管理工具会以 Pinia 为主
- vue devtools 目前还不支持 vue3 的时间旅行
- 完整的 typescript 支持
- 支持同步和异步的actions
- 模块化设计,自动的代码拆分
由于pinia在去年年初才开始引起广泛关注,目前的社区力量相对vuex还比较小,stack overflow 上相关的讨论也不如vuex。
但截止目前(2021-12-24),pinia 已经发布了 v2 版,且在稳定迭代中,社区也在快速增长中,也成为了vuejs的官方状态管理库,希望后续会出现更多的解决方案。
pinia 是轻量级,体积小,适合中小型、低复杂度的项目,对于大型、复杂度高的项目,vuex更适合,也更稳定。
,