天天看點

vue下一代狀态管理Pinia.js 保證你看的明明白白!

1.pinia的簡單介紹
Pinia最初是在2019年11月左右重新設計使用Composition API的 Vue 商店外觀的實驗。
從那時起,最初的原則相同,但 Pinia 适用于 Vue 2 和 Vue 3 。
并且不需要你使用組合 API。
除了安裝和SSR之外,還有其他的 API是一樣的。
并且這些針對 Vue 3 ,并在必要時提供 Vue 2 的相關注釋。
以便 Vue 2 和 Vue 3 的使用者可以閱讀!      
2.為什麼要使用Pina?
Pinia 是 Vue 的存儲庫,
允許您跨元件/頁面共享狀态。
如果您的組合 API,您可能會認為您可以使用簡單的export const state = reactive({})
這對于單頁應用程式來說是正确的,
但如果它是伺服器端的外觀,将您的應用程式顯示給安全漏洞。
但即使在小型單頁應用程式中,您也可以從使用 Pinia 中獲得好處:
1.開發工具支援
2.動作、追蹤的跟蹤
3.熱子產品更換
4.為 JS 使用者提供适當功能的 TypeScript 支援或自動完成
5.伺服器端渲染支援      
安裝
npm install pinia --save      
3.建立檔案夾和檔案-存放資料
在建立 src/store目錄并在其下面建立 index.ts檔案,并導出這個檔案

// src/store/index.ts下的代碼
import { createPinia } from 'pinia'
const store = createPinia()
export default store      
在 main.ts 中引入
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
<!-- 引入 -->
import store from "./store/index"
<!-- 使用store -->
createApp(App).use(router).use(store).mount('#app')      
需求描述
假設我們現在有好幾個子產品。有user子產品。admin子產品。
我們想對這子產品中的資料進行管理。
為了管理友善,後面易于維護。我們決定将這些子產品進行拆分。
于是我們在store下建立 user.ts 檔案,管理這個user子產品的資料。      
user.ts下的資料
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
export const useUserStore = defineStore({
    id: 'userkey', // id必填,且需要唯一
    // state是存放資料的  
    state: () => {
        return {
            name: '于途',
            likelist:[],
            sex:'男',
            work:'寫代碼',
            heigt:'1.70cm'
        }
    },
})      
defineStore的介紹
defineStore 接收兩個參數.
第一個參數:必須是唯一的,多個子產品千萬千萬不能重名。
因為Pinia 會把所有的子產品都挂載到根容器上
第二個參數是一個對象,裡面的選項state和 Vuex 差不多      
4.擷取store中值的第一種方法
<template>
    <div class="pinia">
       <h2> 學習pinia </h2>
       <div> {{ userStore }} </div>
        <div>姓名:{{ userStore.name }}</div>
        <div>性别:{{ userStore.sex }}</div>
        <div>工作:{{ userStore.work }}</div>
        <div>身高:{{ userStore.heigt }}</div>
    </div>
</template>
    
<script setup lang='ts'>
// 引入store中暴露出去的方法
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
</script>      
vue下一代狀态管理Pinia.js 保證你看的明明白白!
擷取store中值的第二種方法-computed
<template>
    <div class="pinia">
       <h2> 學習pinia </h2>
        <div>姓名:{{useStoreName}}</div>
        <div>性别:{{useStoreSex}}</div>
    </div>
</template>
    
<script setup lang='ts'>
// 引入store中暴露出去的方法
import { computed } from 'vue'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
// 使用 computed取擷取值
const useStoreName = computed(() => userStore.name)
const useStoreSex = computed(() => userStore.sex)
</script>      
vue下一代狀态管理Pinia.js 保證你看的明明白白!
提出問題
如果對象上有多個屬性,可以進行結構嗎?
可以的!
使用 pinia 提供的 storeToRefs
我們來看下怎去使用      
5.pinia 提供的 storeToRefs進行結構
<template>
    <div class="pinia">
       <h2> 學習pinia </h2>
        <div>姓名:{{ asName }}</div>
        <div>性别:{{ mysex }}</div>
        <div>工作:{{ work }}</div>
        <div>身高:{{ heigt }}</div>
    </div>
</template>
    
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
// asName 和 mysex 是我取的别名
const { name : asName ,sex:mysex, work, heigt } = storeToRefs(userStore)
</script>      
vue下一代狀态管理Pinia.js 保證你看的明明白白!
6.如何修改 state 中的資料
修改 state 中的資料,可以通過 actions 下的方法。
然後調用 updataName 就可以取修改 state中的name值了
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
export const useUserStore = defineStore({
    id: 'userkey', // id必填,且需要唯一
    // state是存放資料的  
    state: () => {
        return {
            name: '于途',
            likelist:[],
            sex:'男',
            work:'寫代碼',
            heigt:'1.70cm'
        }
    },
    // actions 可以修改state中的值,這裡面提供方法
    actions:{
        // 修改name中的資料
        updataName(name:string){
            this.name=name
        },
    },
})      

調用方法,修改state中的name

<template>
    <div class="pinia">
       <h2> 學習pinia </h2>
        <div>姓名:{{ asName }}</div>
        <div>性别:{{ mysex }}</div>
        <div>工作:{{ work }}</div>
        <div>身高:{{ heigt }}</div>

        <el-button type="primary" @click="changeHander">修改name</el-button>
    </div>
</template>
    
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
// asName 和 mysex 是我取的别名
const { name : asName ,sex:mysex, work, heigt } = storeToRefs(userStore)
const changeHander=()=>{
    userStore.updataName('小玉兔')

    // 這樣我發現也可以,但是不推薦這樣使用。
    // 統一通過 actions 中的方法去修改值
    userStore.work='我換工作了'
}
</script>      
vue下一代狀态管理Pinia.js 保證你看的明明白白!
7.getters的使用
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
export const useUserStore = defineStore({
    id: 'userkey', // id必填,且需要唯一
    // state是存放資料的  
    state: () => {
        return {
            name: '于途',
            likelist:[],
            sex:'男',
            work:'寫代碼',
            heigt:'1.70cm',
            age:26,
        }
    },
    // actions 可以修改state中的值,這裡面提供方法
    actions:{
        // 修改name中的資料
        updataName(name:string){
            this.name=name
        },
    },
    // Getter 完全等同于 Store 狀态的計算值
    getters:{
        // 将姓名進行更改
        getName: (state) => {
            return state.name + 'hahha~!'
        }
    }
})

//使用的頁面.vue
<template>
    <div class="pinia">
       <h2> 學習pinia </h2>
        <div>姓名:{{ asName }}</div>
        <div>性别:{{ mysex }}</div>
        <div>工作:{{ work }}</div>
        <div>身高:{{ heigt }}</div>
        <div>身高:{{ age }}</div>
        <!-- 這裡就直接使用了getters中的方法  -->
          姓名:{{ userStore.getName }}
        <el-button type="primary" @click="changeHander">修改name</el-button>
    </div>
</template>
    
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
// asName 和 mysex 是我取的别名
const { name : asName ,sex:mysex,
   work, heigt,age 
} = storeToRefs(userStore)
const changeHander=()=>{
    userStore.updataName('小玉兔')
}
</script>      
vue下一代狀态管理Pinia.js 保證你看的明明白白!
對于getters的使用的說明
Getter 完全等同于 Store 狀态的計算值 computed.
并不會影響原始資料      
9.異步actions-設定state中的值
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
// 引入接口
import { getUser } from "../https/api";
export const useUserStore = defineStore({
    id: 'userkey', // id必填,且需要唯一
    // state是存放資料的  
    state: () => {
        return {
            name: '于途',
            likelist:[],
        }
    },
    // actions 可以修改state中的值,這裡面提供方法
    actions:{
        // 修改name中的資料 同步
        updataName(name:string){
            this.name=name
        },
        // 異步-擷取遠端的資料
        loadUserList(){
            getUser({}).then(res=>{
                this.likelist = res
            })
        }
        // 使用await和async 第二種方法
        // async loadUserList(){
        //     const list = await getUser({})
        //     console.log('list',list)
        //     this.likelist = list
        // }
    },
})

使用的頁面
<template>
    <div class="pinia">
       <h2> 學習pinia </h2>
         資料 {{ userStore.likelist}}
        <el-button type="primary" @click="changeHander">擷取遠端資料</el-button>
    </div>
</template>
    
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
const changeHander=()=>{
    // 異步調用
    userStore.loadUserList() // 加載所有資料
}      
vue下一代狀态管理Pinia.js 保證你看的明明白白!
10.actions 中互相調用方法
很多時候,我們可能會出現 actions中互相去調用方法。
這個時候怎麼去處理呢? 
通過this.方法名(參數)

//src/store/user.ts 檔案
import { defineStore } from 'pinia'
// 引入接口
import { getUser } from "../https/api";
export const useUserStore = defineStore({
    id: 'userkey', // id必填,且需要唯一
    // state是存放資料的  
    state: () => {
        return {
            name: '于途',
            likelist:[],
        }
    },
    // actions 可以修改state中的值,這裡面提供方法
    actions:{
        // 修改name中的資料 同步
        updataName(name:string){
            this.name=name
        },
        // 異步-擷取遠端的資料
        loadUserList(){
            getUser({}).then(res=>{
                this.likelist = res
                this.sayHi('互相調用方法')
            })
        },
        sayHi(mess:string){
            console.log('loadUserList方法中調用了sayHi',mess)
        }
    },
})

使用的頁面.vue
<template>
    <div class="pinia">
       <h2> 學習pinia </h2>
        資料 {{ userStore.likelist}}
        <el-button type="primary" @click="changeHander">擷取遠端資料</el-button>
    </div>
</template>
    
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
const changeHander=()=>{
    // 異步調用
    userStore.loadUserList() // 加載所有資料
}
</script>      
vue下一代狀态管理Pinia.js 保證你看的明明白白!
11.資料持久化-sessionStorage 或 localStorage
我們都知道,vuex重新整理後,資料會丢失。
這個時候我們需要将資料進行持久化。
我們可以考慮sessionStorage或者localStorage

//src/store/user.ts 檔案
import { defineStore } from 'pinia'
// 引入接口
import { getUser } from "../https/api";
export const useUserStore = defineStore({
    id: 'userkey', // id必填,且需要唯一
    // state是存放資料的  
    state: () => {
        return {
            // 資料持久化使用的是sessionStorage
            name: sessionStorage.getItem('name') ? sessionStorage.getItem('name') :  '于途',
            likelist:[],
        }
    },
    actions:{
        // 修改name中的資料 同步
        updataName(name:string){
            sessionStorage.setItem('name', name)
            this.name=name
        },
    },
})


<template>
    <div class="pinia">
       <h2> 學習pinia </h2>
         姓名 {{ userStore.name}}
        <el-button type="primary" @click="changeHander">該變值</el-button>
    </div>
</template>
    
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
const changeHander=()=>{
    // 異步調用
    userStore.updataName('我改變了姓名') 
}
</script>      
vue下一代狀态管理Pinia.js 保證你看的明明白白!
12.跨子產品修改資料
雖然我不建議跨子產品修改資料。
因為這樣可能會導緻你的應用資料流向變得難以了解。
但是有些時候确實需要跨子產品修改資料。
那麼pinia怎麼去處理跨子產品修資料呢?
下面我們一起來探索跨子產品修改資料!
假設admin子產品需要去修改user子產品中的資料      
admin.ts代碼如下
//src/store/admin.ts 檔案
import { defineStore } from 'pinia'
// 引入user子產品
import { useUserStore } from './user'
export const adminUserStore = defineStore({
    id: 'adminkey', 
    actions:{
      // 通過引入的useUserStore子產品,然後去觸發它裡面對應的方法。
       editUserModuleValue(name:string){
           //  userStore可以看見整個user子產品中的資料和方法
           let userStore=useUserStore()
           console.log('userStore',userStore)
           userStore.updataName(name)
       }
    },
})      
user.ts代碼
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
// 引入接口
export const useUserStore = defineStore({
    id: 'userkey', // id必填,且需要唯一
    // state是存放資料的  
    state: () => {
        return {
            name: '于途',
            likelist:[],
            sex:'男',
            work:'寫代碼',
            heigt:'1.70cm'
        }
    },
    actions:{
        // 修改name中的資料 同步
        updataName(name:string){
            this.name=name
        },
    },
})      
頁面的使用
<template>
    <div class="pinia">
       <h2> 學習pinia </h2>
         姓名 {{ userStore.name}}
        <el-button type="primary" @click="changeHander">該變值</el-button>
    </div>
</template>
    
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
// 引入admin子產品
import { adminUserStore } from '../../store/admin'
// 引入user子產品
import { useUserStore } from '../../store/user'
const adminStore = adminUserStore()
const userStore = useUserStore()
// dmin子產品需要去修改user子產品中的資料
const changeHander=()=>{
    adminStore.editUserModuleValue('資料資料')
}
</script>      
尾聲

遇見問題,這是你成長的機會,如果你能夠解決,這就是收獲。

繼續閱讀