文章目录
引入 Pinia
首先在 main.ts 中引入 pinia,通过 createPinia 创建 pinia 实例,然后挂载到 Vue 根实例上。
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const app = createApp(App)
/** 创建 pinia 实例 */
const pinia = createPinia()
/** 挂载到 Vue 根实例上 */
app.use(pinia)
app.mount('#app')
创建 Store
首先在 src 下创建 store/index.ts 文件,然后通过 defineStore 对仓库进行配置。
import { defineStore } from 'pinia'
/** main 相当于为容器起一个名字 */
export const useStore = defineStore('main', {
state: () => {
return {
msg: 'Hello World'
}
},
getters: {},
actions: {}
})
现在每个页面和组件都可以通过 Pinia 方法读取到全局状态 msg。
state: 用来存储全局状态数据。
getters:相当于组件中的计算属性,有缓存功能。
actions:用来修改全局状态数据。
在组件中读取 Store 数据
在 CostPaymentList 组件中,通过 store/index.ts 文件暴露出来的 useStore 得到 store 实例,就可以在组件里使用 Store 里面的全局状态了。
<template>
<h1>CostPaymentList Page</h1>
<!-- 在 template 中,有两种方式可以获取 Store 中的全局状态 -->
<p>{{ store.msg }}</p>
<p>{{ store.$state.msg }}</p>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { useStore } from '../../store/index'
export default defineComponent({
name: 'CostPaymentList',
setup() {
const store = useStore()
/** 在 setup 中,有两种方式可以获取 Store 中的全局状态 */
console.log(store.msg)
console.log(store.$state.msg)
return {
store
}
},
})
</script>
打印一下 store:

在组件中修改 Store 数据
- 首先在 Store 仓库中添加一个
count全局状态。
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
state: () => {
return {
count: 0
}
}
})
- 创建一个新的组件,并为页面中的按钮添加
click事件,在事件里面修改全局状态count。
<template>
<h1>HelloWorld Page</h1>
<p>{{ store.count }}</p>
<button @click="handleAddCount">增加</button>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { useStore } from '../store/index'
export default defineComponent({
name: 'HelloWorld',
setup() {
const store = useStore()
const handleAddCount = () => {
store.count++
}
return { store, handleAddCount }
}
})
</script>
- 把新创建的组件引入到 App 组件中。
<template>
<CostPaymentList />
<hr />
<HelloWorld />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import CostPaymentList from 'views/finance/CostPaymentList.vue'
import HelloWorld from './components/HelloWorld.vue'
export default defineComponent({
name: 'App',
components: {
CostPaymentList,
HelloWorld
}
})
</script>
当点击按钮时,两个组件的数据都会同时变化。

对 Store 进行解构
在 CostPaymentList 组件对 Store 进行解构,并在 template 中直接使用解构后的数据。
<template>
<h1>CostPaymentList Page</h1>
<p>{{ count }}</p>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { useStore } from '../../store/index'
export default defineComponent({
name: 'CostPaymentList',
setup() {
const { count } = useStore()
return {
count
}
},
})
</script>
然后点击 Hello World 组件中的按钮,发现 CostPaymentList 组件中的数据并未同步更新。

打印一下解构后的 count:
console.log({count}, typeof count)

可以发现 count 是 number 类型,并非是响应式结构,所以才会丢失响应。
如果需要解构后还保持响应式,需要使用到 pinia 暴露出来的 storeToRefs。
<template>
<h1>CostPaymentList Page</h1>
<p>{{ count }}</p>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useStore } from '../../store/index'
export default defineComponent({
name: 'CostPaymentList',
setup() {
const store = useStore()
const { count } = storeToRefs(store)
return {
count
}
},
})
</script>
通过 storeToRefs 可以使解构出来的数据拥有响应能力。

打印一下 count:

可以看到,此时的 count 是作了 ref 响应式处理。
修改 Store 状态数据的多种方式
修改 Store 中状态方式除了上面所说的方式,还有三种方式。
- 通过
$patch同时修改多个状态。
<template>
<h1>HelloWorld Page</h1>
<p>{{ count }}</p>
<p>{{ name }}</p>
<button @click="handleUpdateStore">更新</button>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useStore } from '../store/index'
export default defineComponent({
name: 'HelloWorld',
setup() {
const store = useStore()
const handleUpdateStore = () => {
store.$patch({
count: 100,
name: 'new_sjw'
})
}
return { ...storeToRefs(store), handleUpdateStore }
}
})
</script>

如果想同时修改多个状态,一定要使用 $patch 吗?
并不是,通过多条语句也可以达到这个目的:
const handleUpdateStore = () => {
store.count = 100
store.name = 'new _sjw'
}
之所以使用 $patch,是因为 Pinia 的官方网站,已经明确表示 $patch 的方式是经过优化的,会加快修改速度,对程序的性能有很大的好处。所以如果是多个状态同时更新据,推荐使用 $patch 方式更新。
- 通过 $patch 加函数的形式修改状态
第一种方式中,$patch 接收一个对象,适合基本数据类型的修改,不适合复杂数据的修改(如数组、对象)。
针对这个问题,$patch 可以通过接收一个函数来处理复杂数据:
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
state: () => {
return {
count: 0,
name: 'sjw',
list: [
{ des: '1 号篮球员' },
{ des: '2 号篮球员' },
{ des: '3 号篮球员' }
]
}
}
})
<template>
<h1>HelloWorld Page</h1>
<p>{{ count }}</p>
<p>{{ name }}</p>
<ul>
<li v-for="(item, index) in list" :key="index">{{ item.des }}</li>
</ul>
<button @click="handleUpdateStore">更新</button>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useStore } from '../store/index'
export default defineComponent({
name: 'HelloWorld',
setup() {
const store = useStore()
const handleUpdateStore = () => {
store.$patch((state) => {
/** 在这里不要对 state 进行解构,否则会丢失响应式 */
state.count++
state.name = 'new_sjw'
state.list[0].des = '200 号足球员'
})
}
return { ...storeToRefs(store), handleUpdateStore }
}
})
</script>
- 通过调用 actions 来修改状态
对于复杂的修改操作,可以在 actions 中封装一个方法,然后在组件调用该方法即可。
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
state: () => {
return {
count: 0,
name: 'sjw',
list: [
{ des: '1 号篮球员' },
{ des: '2 号篮球员' },
{ des: '3 号篮球员' }
]
}
},
actions: {
changeState() {
this.count++
this.name = 'new_sjw'
this.list[0].des = '200 号足球员'
}
}
})
<script lang="ts">
import { defineComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useStore } from '../store/index'
export default defineComponent({
name: 'HelloWorld',
setup() {
const store = useStore()
const handleUpdateStore = () => {
store.changeState()
}
return { ...storeToRefs(store), handleUpdateStore }
}
})
</script>
在使用
actions的时候,不能时候箭头函数,否则this为undefined。
Getters 的使用
Pinia 中的 Getter 和组件中的计算属性(Computer)作用几乎一样,可以对 State 里面的状态进一步处理。
- 首先在 Store 中声明一个 Getter 属性,它对
msg进行了处理。
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
state: () => {
return {
msg: 'Hello'
}
},
getters: {
logMsg(state) {
return state.msg + ' Wold!'
}
}
})
- 在组件中的使用方式和
state里面的状态一样,直接调用即可。
<template>
<h1>CostPaymentList Page</h1>
<p>{{ logMsg }}</p>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useStore } from '../../store/index'
export default defineComponent({
name: 'CostPaymentList',
setup() {
const store = useStore()
const { logMsg } = storeToRefs(store)
return {
logMsg
}
},
})
</script>
验证 Getter 的缓存特性:
1.首先在 logMsg 中添加 console.log() 语句,保证 logMsg 每次被调用时都能知道。
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
state: () => {
return {
msg: 'Hello'
}
},
getters: {
logMsg(state) {
console.log('调用了 logMsg')
return state.msg + ' Wold!'
}
}
})
- 然后在组件中编写一个方法,使其能够多次调用
logMsg。
<template>
<h1>CostPaymentList Page</h1>
<button @click="handleLogMsg">调用</button>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useStore } from '../../store/index'
export default defineComponent({
name: 'CostPaymentList',
setup() {
const store = useStore()
const { logMsg } = storeToRefs(store)
const handleLogMsg = () => {
console.log(logMsg.value)
}
return {
logMsg,
handleLogMsg
}
},
})
</script>

可以发现,多次调用 logMsg 时,只打印了一次“调用了 logMsg”,说明 logMsg 真正被调用次数的只有一次,后续的调用都是从缓存中返回数据。
- 在组件中编写一个可以更改
msg状态的方法。
<template>
<h1>CostPaymentList Page</h1>
<button @click="handleLogMsg">调用</button>
<button @click="handleChangeMsg">更改</button>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { storeToRefs } from 'pinia'
import { useStore } from '../../store/index'
export default defineComponent({
name: 'CostPaymentList',
setup() {
const store = useStore()
const { msg, logMsg } = storeToRefs(store)
const handleLogMsg = () => {
console.log(logMsg.value)
}
const handleChangeMsg = () => {
msg.value += 'sjw-'
console.log(logMsg.value)
}
return {
logMsg,
handleLogMsg,
handleChangeMsg
}
},
})
</script>

可以发现,当 msg 发生变化时,logMsg 都会随着执行一次,清除之前的缓存。
也可以在 Getters 中使用 this。
Store 的互相调用
当项目存在多个 Store 时,这些 Store 之间可以互相调用。
- 首先,新增一个新的
userStore,并声明一个storeName状态。
/* user.ts */
import { defineStore } from 'pinia'
export const userStore = defineStore('user', {
state: () => {
return {
storeName: 'userStore'
}
}
})
- 在其它 Store 中引入
userStore并调用storeName属性。
/* index.ts */
import { defineStore } from 'pinia'
import { userStore } from './user'
export const useStore = defineStore('main', {
state: () => ({
msg: 'Hello'
}),
actions: {
getUserStore() {
console.log(userStore().storeName)
}
}
})
2667

被折叠的 条评论
为什么被折叠?



