pinia

认识Pinia(和vuex对比)

Pinia 是 Vue 的专属的最新 状态管理,是 Vuex 状态管理工具的替代品,pinia更适配vue3

和vuex的区别

1.提供更加简单的API (去掉了mutation)
2.提供符合,Composition组合式风格的API(和 Vue3 新语法统一)
3.去掉了modules的嵌套结构,每一个store都是一个独立的模块,不再是vuex的单一组件树
4.配合TypeScript更加友好,提供可靠的类型推断
5.不再有命名空间的概念,不需要记住它们的复杂关系

Pinia安装和基本使用

npm install pinia
创建js文件,注册导入Pinia
创建store文件夹,在里面创建index.js

1
2
3
import { createPinia } from 'pinia'
const pinia = createPinia() //创建pinia实例
export default pinia

在main.js中挂载pinia实例

1
2
3
4
5
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

createApp(App).use(pinia).mount('#app')

pinia管理数据

后续希望Pinia管理的数据,在store文件夹创建对应的.js文件,每个想要定义的单独数据单独放在一个store里
在每个单独的store里面定义仓库defineStore()返回的结果是一个函数,一返回的函数统一用useID命名方式,如useCounter
diefineStore(),在里面传入第一个参数作为仓库的表示,
定义store后会自动管理,直接导出即可

1
2
3
4
5
6
7
8
import { defineStore } from 'pinia'

const useCounter = defineStore('storeCounter',{
state:()=>({
count:100
})
})
export default useCounter

要使用时Home.vue

1
2
import useCounter from '@/store/counter'
const counterStore = useCounter()

使用数据<h2>count:{{counterStore.count}}</h2>
不需要再.state,直接用数据就可以了

Store

认识Store

一个store (如 Pinia)是一个实体,它会持有为绑定到你组件树的状态和业务逻辑,有点像始终存在,并且每个人都可以读取和写入的组件
可以在应用程序中定义任意数量的store来管理你的状态
Store有三个核心概念:state、 getters、 actions;
等同于组件的data、computed、methods;
一旦store被实例化,你就可以直接在 store 上访问 state、getters 和 actions 中定义的任何属性

定义Store

使用defineStore()定义,返回的函数统一用useX命名方式,具体前面有写
当定义好后,在浏览器调试工具里面可以看到,如图
URL的hash

使用数据注意–解构响应性

store不能直接解构,不然会让数据失去响应式:

  1. 不解构
    1
    2
    3
    4
    5
    import useCounter from '@/store/counter'
    const counterStore = useCounter()
    function changeCount(){
    counterStore.count++ //pinia里面可以直接这样做
    }
    使用数据<h2>count:{{counterStore.count}}</h2>,没问题
  2. 解构错误使用
    1
    2
    3
    4
    5
    6
    import useCounter from '@/store/counter'
    const counterStore = useCounter()
    const {count} = counterStore //这里解构了
    function changeCount(){
    counterStore.count++ //pinia里面可以直接这样做
    }
    使用解构的数据<h2>count:{{count}}</h2>
    刚开始能展示出来,但是数据变化count不会跟着变,失去了响应式
  3. 解构正确使用(toRefs)
    如果你非要解构+响应式,使用toRefs
    1
    2
    3
    4
    5
    6
    7
    import useCounter from '@/store/counter'
    import { toRefs } from 'vue'
    const counterStore = useCounter()
    const {count,sum,age} = toRefs(counterStore) //这里解构了
    function changeCount(){
    counterStore.count++ //pinia里面可以直接这样做
    }
    使用解构的数据<h2>count:{{count}}</h2>,现在能成功响应
  4. 解构正确使用(storeToRefs)
    要解构+响应式,也可以用Pinia提供的storeToRefs
    1
    2
    3
    4
    5
    6
    7
    import useCounter from '@/store/counter'
    import { storeToRefs } from 'pinia'
    const counterStore = useCounter()
    const {count,sum,age} = storeToRefs(counterStore) //这里解构了
    function changeCount(){
    counterStore.count++ //pinia里面可以直接这样做
    }
    使用解构的数据<h2>count:{{count}}</h2>,现在能成功响应

Pinia核心概念–State

改变State

  1. 读取和写入 state
    默认情况下,可以通过 store 实例访问状态来直接读取和写入状态
    1
    2
    3
    const counterStore =useCounter()
    counterStore.counter++
    counterStore.name="nienie"
  2. 重置state$reset()
    调用 store 上的 $reset() 方法将状态 重置 到其初始值;
    除了直接用 store.counter++修改store,还可以调用 $patch 方法
    它允许使用部分state对象同时应用多个更改
    1
    2
    3
    4
    5
    const counterStore =usecounter()
    counterStore.$patch({
    counter:100.
    name: "nie"
    })

    自己的方法不加$,如果是他给我们提供的一般有$

Pinia核心概念–Getters

getters相当于store的计算属性,可以在 getters 中定义一个函数,这个函数会返回一个值,这个值会缓存,只有当依赖的 state 发生变化时才会重新计算
getters函数中默认接收一个state作为参数

Getters基本使用

一个getters中也可以引入另外一个getters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { defineStore } from 'pinia'

const useCounter = defineStore('storeCounter',{
state:()=>({
count:100
}),
getters:{
doubleCount(state){
return state.count * 2
},
// getters中可以引入另外一个getters
doubleCountPlusOne(){
return this.doubleCount + 1
}
}
})
export default useCounter

使用:

1
2
import useCounter from '@/store/counter'
const counterStore = useCounter()

<h2>count1:{{counterStore.doubleCount}}</h2>
<h2>count2:{{counterStore.doubleCountPlusOne}}</h2>
同样不需要写.getters,使用很简洁

getters也支持返回一个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { defineStore } from 'pinia'

const useCounter = defineStore('storeCounter',{
state:()=>({
count:100,
friends:[
{id:111,name:"雾刃"},
{id:112,name:"枫糖"},
{id:113,name:"松瑰"}
]
}),
getters:{
doubleCount(state){
return state.count * 2
},
// getters中可以引入另外一个getters
doubleCountPlusOne(){
return this.doubleCount + 1
},
getFriendsById(){
return function(id){
for(let i=0;i<state.friends.length;i++){
const item = state.friends[i]
if(item.id === id){
return item
}
}
}
}
}
})
export default useCounter

<h2>count2:{{counterStore.getFriendsById(111)}}</h2>返回{id:111,name:"雾刃"}

getters中可以使用别的store中的数据

导入别的store,然后在getters中获取别的store信息,再使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { defineStore } from 'pinia'
import { useUser } from '@/store/user'
const useCounter = defineStore('storeCounter',{
state:()=>({
count:100,
friends:[
{id:111,name:"雾刃"},
{id:112,name:"枫糖"},
{id:113,name:"松瑰"}
]
}),
getters:{
showMessage(state){
const userStore = useUser() //中获取别的store信息
return `姓名:${userStore.name}`
}
}
})
export default useCounter

Pinia核心概念–Actions

  • Actions 相当于组件中的 methods
  • 用 defineStore()中的 actions 属性定义,非常适合定义业务逻辑
  • 和getters一样,在action中可以通过this访问整个store实例的所有操作
  • actions是支持异步操作的,并且可以编写异步函数,在函数中使用await
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    import { defineStore } from 'pinia'

    const useCounter = defineStore('storeCounter',{
    state:()=>({
    count:100,
    friends:[
    {id:111,name:"雾刃"},
    {id:112,name:"枫糖"},
    {id:113,name:"松瑰"}
    ]
    }),
    getters:{
    doubleCount(state){
    return state.count * 2
    },
    // getters中可以引入另外一个getters
    doubleCountPlusOne(){
    return this.doubleCount + 1
    },
    getFriendsById(){
    return function(id){
    for(let i=0;i<state.friends.length;i++){
    const item = state.friends[i]
    if(item.id === id){
    return item
    }
    }
    }
    }
    },
    actions:{
    increment(){},
    //actions是支持异步操作的
    async fetchHomeMultidata(){}
    const res=await fetch("http://....")
    const data = await res.json()
    this.banners = data.data.banner.list
    this.recommend = data.data.recommend.list
    return data
    }
    }
    )
    export default useCounter

Pinia基础使用和持久化工具(旧笔记)

创建项目(按照官方文档安装)

使用 Vite 创建一个空的 Vue3项目
npm ceate vue@latest
这里面的pinia选的No,这里根据官方文档安装pinia,学会后后面直接选Yes
https://pinia.vuejs.org/zh/
这里是vue3使用方法,官方文档也有2的使用方法
首先导包挂载,在项目的main.js中修改代码

1
2
3
4
5
6
7
8
9
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia() //创建pinia实例
const app = createApp(App) //创建根实例

app.use(pinia)
app.mount('#app')

store

有Option Store和Setup Store,推荐使用后者,模块化,更易维护和操作
在src文件夹中创建store文件夹,在里面创建仓库名.js,每个仓库之间是独立的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { definestore }from 'pinia'
import{ ref } from 'vue'
//定义store,一但调用这个函数useCounterStore就可以使用return的内容
// definestore(仓库的唯一标识,()=>{...})
//一个命名规范:导出的函数名都用use开头,store结尾,中间是仓库名
export const useCounterStore = defineStore('counter',()=>{
//声明数据 state-countconst
count =ref(0)// 声明操作数据的方法 action(普通函数)
const addCount = () =>count.value++
const subCount = () =>count.value--
//声明基于数据派生的计算属性getters
const double = computed(()=>count.alue * 2)

//声明数据 state - msg
const msg = ref('hello,pinia')
return
{count,
msg,
addCount,
subCount,
double
}
})

action异步实现

pinia的action不需要考虑同步异步,都支持,和组件中获取异步数据的写法完全一致

storeToRefs工具函数

理解:如果直接导入仓库的函数,然后再页面直接结构使用return的数据的值。不进行处理,那么数据会丢失响应式(函数不会,函数可以直接解构)
改进:先导入import {storeToRefs} from ‘pinia’ 然后在结构的时候使用一个方法storeToRefs(函数名)

Pinia持久化插件

官方文档:https://prazdevs.github.io/pinia-plugin-persistedstate/zh/

  1. 安装插件 pinia-plugin-persistedstate
    官方文档说版本要高于2.0.0,在项目package.json文件夹里的dependencies里面有pinia的版本

    1
    npm i pinia-plugin-persistedstate
  2. 在main.js中将插件添加到Pinia实例上

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    //将插件添加到Pinia实例上
    //官方文档
    import{createPinia}from 'pinia'
    import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
    const pinia = createPinia()
    pinia.use(piniaPluginPersistedstate)

    ...
    //完整的main.js
    import { createApp } from 'vue'
    import { createPinia } from 'pinia'
    // 导入持久化的插件
    import persist from 'pinia-plugin-persistedstate'

    import App from './App.vue'
    const pinia = createPinia() // 创建Pinia实例
    const app = createApp(App) // 创建根实例
    app.use(pinia.use(persist)) // pinia插件的安装配置
    app.mount('#app') // 视图的挂载eatePinia().use(persist))
  3. 配置 store/counter.js
    在修改数据的时候优先往本地存,在你刷新的时候优先从本地获取
    开启当前模块的持久化:在要配置的.js文件中store的第三个参数添加{
    persist: true
    }
    完成后重启项目,在F12vue中可以看到,也可以在F12的Application中看到存储到本地的数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import { defineStore } from 'pinia'
    import { computed, ref } from 'vue'

    export const useCounterStore = defineStore('counter', () => {
    ...
    return {
    count,
    doubleCount,
    increment
    }
    }, {
    persist: true //开启当前模块的持久化
    })
  4. 其他配置看官网文档