Skip to content

示例项目克隆: https://gitee.com/yyt363045841/example-of-pintia-project.git

什么是 Pinia

  • 一个状态管理库
  • 类似:redux,vuex
  • 集中式状态管理:不同组件的数据共享(但不是所有数据)
  • 处理的是一个 reactive 响应式对象

启用 pinia

ts
const app = createApp(App)
app.use(createPinia())//创建并安装

此时控制台会输出 "count" store installed (在组件中调用 useXXXStoreexport 函数的时候)。

定义 pinia 存储仓库

.src/store 中存储 pinia 数据。

ts
import { defineStore } from "pinia";

export const useCountStore = defineStore('count',{
    state:()=>{
        return {
            sum:6
        }
    }
})

在组件中读取数据

ts
let useTalkStore = useLovetaikStore()//调用暴露函数获取数据

渲染

html
<div class="talk">
	<button @click="getAword">get a word</button><br> 
	<ul v-if="useTalkStore.talklist.length > 0">
		<li v-for="word in useTalkStore.talklist" :key="word.id">{{ word.title }}</li>
	</ul>
</div>

[[响应式基础#特例]]:虽然 useXXX 其中的数据是 ref 对象,但是在 reactive 中这个对象中的值的调用会被自动解包。

类型标注

ts
import { defineStore } from "pinia";

interface GameData {
  nowChoose: number | null;
  alertShow: boolean;
}

export const useGameData = defineStore("windowShow", {
  state: (): GameData => ({//类型注解
    nowChoose: null,
    alertShow: false
  })
});

修改数据

  1. 直接修改拿到的 store 对象属性
ts
const countStore = useCountStore();//获取store

function doAdd() {
    countStore.sum += add.value;
}
  1. 使用 $patch 方法,同时应用多个修改
ts
function doAdd() {
    countStore.$patch({
        sum: countStore.sum + add.value,
    });
}
  1. 调用 store.action 中定义的方法(进行逻辑处理、复用
ts
import { defineStore } from "pinia";

export const useCountStore = defineStore('count',{
    actions:{
        increment(value:number){
            this.sum++
        }
    },
    state:()=>{
        return {
            sum:6
        }
    }
})
ts
function doAdd() {
    countStore.increment(add.value);
}

storeToRefs

解构 store 数据的时候,不要用 toRefs,因为他会把 store 对象中的所有数据都变为响应式的。 使用 storeToRefs,可以只得到解构的响应式对象。

getters

相当于计算属性不要将异步逻辑写在这里!

  • 用于对 pinia 管理的数据进行再次加工(封装计算逻辑)
  • 一旦 state 状态更新,getter 会自动更新
  • 确保 state 只存储基本状态
ts
export const useCountStore = defineStore('count',{
    actions:{
        increment(value:number){
            this.sum++
        }
    },
    state:()=>{
        return {
            sum:6
        }
    },
    getters:{
        watchCount:int (state){
            return state.sum * 10//随着sum的更新而更新,等价于return this.num * 10
        }
        watchCount:state => return state*10//箭头函数简写,但是不能用this
    }
})

pinia 中的数据所有组件都可以读取,这个 getter 也相当于可共享的计算属性

$subscribe

store 管理的状态发生改变时调用。

ts
countStore.$subscribe((mutation, state) => {
    console.log(mutation, state);//
});

浏览器本地数据存储

存储

ts
useTalkStore.$subscribe((mutation, state) => {
    localStorage.setItem('talkList',JSON.stringify(state.talkList))
})

读取

ts
export const useLovetalkStore = defineStore('lovetalk', {
    state: (): { talkList: List[] } => ({
        talkList:JSON.parse(localStorage.getItem('talkList') as string) || []
        //getItem的返回值为string | null,因此要将返回类型断言为string以通过类型检查
        //第一次进入本地存储并不存在该项,因此要将它初始化为[]空数组
    }) 
});

Store 的组合式写法

和 vue 组件相同,reactive,ref 定义响应式数据,正常写函数,最终将其 return 出去即可。

ts
import { reactive } from "vue";    
export const useTalkStore = defineStore('loveTalk',()=>{
    let talkList = reactive(JSON.parse(localStorage.getItem('talkList') as string) || []);
    async function addTalk() {
        const { data: { content: title } } = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json');
        let obj: List = {
            id: nanoid(),
            title: title
        };
        talkList.push(obj);
    }
    return {
        talkList,
        addTalk
    }
})

调用

ts
import { useTalkStore } from '@/store/Lovetalk';
const talkStore = useTalkStore()
//调用方法即可

actions

处理 store 的业务逻辑,可以用异步