Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。Pinia 是一个强大而灵活的状态管理库,它的设计目标是让开发者可以更加轻松和高效地管理 Vue.js 应用程序的状态。
安装
yarn add pinia
// # 或者使用 npm
npm install pinia
基本示例
- 首先创建一个 Store
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => {
return { count: 0 }
},
// 也可以定义为
// state: () => ({ count: 0 })
actions: {
increment() {
this.count++
},
},
});
//高级的用例定义一个Store
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
})
- 在组件中使用 Store
import { useCounterStore } from '@/stores/counter'
export default {
setup() {
const counter = useCounterStore()
counter.count++
// 带自动补全 ✨
counter.$patch({ count: counter.count + 1 })
// 或使用 action 代替
counter.increment()
},
}
Store
- 定义 Store
import { defineStore } from 'pinia'
// useStore 可以是 useUser、useCart 之类的任何东西
// 第一个参数是应用程序中 store 的唯一 id
export const useStore = defineStore('main', {
// other options...
})
- 使用 store
import { useStore } from '@/stores/counter'
export default {
setup() {
const store = useStore()
return {
// 您可以返回整个 store 实例以在模板中使用它
store,
}
},
}
State
state 是 store 的核心部分。 我们通常从定义应用程序的状态开始。 在 Pinia 中,状态被定义为返回初始状态的函数。
- State
import { defineStore } from 'pinia'
const useStore = defineStore('storeId', {
// 推荐使用 完整类型推断的箭头函数
state: () => {
return {
// 所有这些属性都将自动推断其类型
counter: 0,
name: 'Eduardo',
isAdmin: true,
}
},
})
- 访问 state
const store = useStore()
store.counter++; //修改
//重置状态
store.$reset()
- 选项 API
import { useStore } from '../stores/counterStore'
export default {
setup() {
const store = useStore()
return { store }
}
}
- 改变状态
store.$patch({
counter: store.counter + 1,
name: 'Abalam',
})
- 替换state
store.$state = { counter: 666, name: 'Paimon' }
Getters
Getter 完全等同于 Store 状态的 计算值。 它们可以用 defineStore() 中的 getters 属性定义。 与计算属性一样,您可以组合多个 getter。 通过 this 访问任何其他 getter。直接访问任何 getter 作为 store 的属性(与 state 属性完全一样)。
- Getter
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2,
},
})
- 在 store 实例上访问 getter
<template>
<p>Double count is {{ store.doubleCount }}</p>
</template>
<script>
export default {
setup() {
const store = useStore()
return { store }
},
}
</script>
- 将参数传递给 getter
export const useStore = defineStore('main', {
getters: {
getUserById: (state) => {
return (userId) => state.users.find((user) => user.id === userId)
},
},
})
//组件中/////////
<script>
export default {
setup() {
const store = useStore()
return { getUserById: store.getUserById }
},
}
</script>
<template>
<p>User 2: {{ getUserById(2) }}</p>
</template>
- 访问其他 Store 的getter
import { useOtherStore } from './other-store'
export const useStore = defineStore('main', {
state: () => ({
// ...
}),
getters: {
otherGetter(state) {
const otherStore = useOtherStore()
return state.localData + otherStore.data
},
},
})
Actions
Actions 相当于组件中的 methods。
- actions
export const useMainStore = defineStore('main', {
state: () => ({
counter: 0,
}),
actions: {
increment() {
this.counter++
},
randomizeCounter() {
this.counter = Math.round(100 * Math.random())
},
},
})
- 在组件中调用 actions
export default defineComponent({
setup() {
const main = useMainStore()
// Actions 像 methods 一样被调用:
main.randomizeCounter()
return {}
},
})
- 访问其他 store 操作
import { useAuthStore } from './auth-store'
export const useSettingsStore = defineStore('settings', {
state: () => ({
// ...
}),
actions: {
async fetchUserPreferences(preferences) {
const auth = useAuthStore()
if (auth.isAuthenticated) {
this.preferences = await fetchPreferences()
} else {
throw new Error('User must be authenticated')
}
},
},
})
插件
使用 pinia.use() 将插件添加到 pinia 实例中。 最简单的例子是通过返回一个对象为所有Store添加一个静态属性
import { createPinia } from 'pinia'
// 为安装此插件后创建的每个store添加一个名为 `secret` 的属性
// 这可能在不同的文件中
function SecretPiniaPlugin() {
return { secret: 'the cake is a lie' }
}
const pinia = createPinia()
// 将插件提供给 pinia
pinia.use(SecretPiniaPlugin)
// 在另一个文件中
const store = useStore()
store.secret // 'the cake is a lie'
Pinia 插件是一个函数,可以选择返回要添加到 store 的属性。 它需要一个可选参数,一个 context:
export function myPiniaPlugin(context) {
context.pinia // 使用 `createPinia()` 创建的 pinia
context.app // 使用 `createApp()` 创建的当前应用程序(仅限 Vue 3)
context.store // 插件正在扩充的 store
context.options // 定义存储的选项对象传递给`defineStore()`
// ...
}
pinia.use(myPiniaPlugin)
扩充 store。您可以通过简单地在插件中返回它们的对象来为每个 store 添加属性:
pinia.use(() => ({ hello: 'world' }))
//您也可以直接在 store 上设置属性
pinia.use(({ store }) => {
store.hello = 'world'
})
//
pinia.use(({ store }) => {
store.hello = 'world'
// 确保您的打包器可以处理这个问题。 webpack 和 vite 应该默认这样做
if (process.env.NODE_ENV === 'development') {
// 添加您在 store 中设置的任何 keys
store._customProperties.add('hello')
}
})
vue3 中 使用pinia
- 安装 npm install pinia
- 在main.ts文件中导入createPinia函数并将Pinia插件与Vue应用程序绑定
使用 createPinia() 函数创建并初始化Pinia插件实例,将其与Vue应用程序绑定使用app.use(pinia)。至此,我们就可以使用Pinia来管理Vue应用程序的状态了。
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
const app = createApp(App);
const pinia = createPinia();
app.use(pinia);
app.mount('#app');
- Pinia的核心,Store、State、Getter、Action就不在啰嗦了。
- 创建一个Vue组件,并在组件中使用Pinia提供的store。
const useMovieListStore = defineStore('movie',{
state: () => ({
isShow: true,
movies: [],
}),
getters: {
getIsShow() {
return this.isShow
},
getMovies() {
return this.movies
},
},
actions: {
setIsShow(value) {
this.isShow = value
},
async fetchMovies() {
const response = await fetch('https://api.movies.com/movies')
const data = await response.json()
this.movies = data
},
},
})
export default useMovieListStore;