vue3探索——5分鐘快速上手大菠蘿pinia

来源:https://www.cnblogs.com/cry0-0/archive/2023/09/10/17691177.html
-Advertisement-
Play Games

溫馨提示:本文以vue3+vite+ts舉例,vite配置和ts語法側重較少,比較適合有vuex或者vue基礎的小伙伴們兒查閱。 安裝pinia yarn yarn add pinia npm npm install pinia pnpm pnpm add pinia 1-開始 方式一:在main. ...


溫馨提示:本文以vue3+vite+ts舉例,vite配置和ts語法側重較少,比較適合有vuex或者vue基礎的小伙伴們兒查閱。

安裝pinia

  • yarn
yarn add pinia
  • npm
npm install pinia
  • pnpm
pnpm add pinia

1-開始

方式一:在main.ts中直接引入pinia

src/main.ts 中引入pinia(根存儲),並傳遞給應用程式。

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'

// 1-創建一個 pinia(根存儲)
import { createPinia } from 'pinia'

const app = createApp(App)

// 2-告訴應用程式,我們將使用pinia
const pinia = createPinia();
// 以插件形式傳遞給app
app.use(pinia);

app.mount('#app');

方式二(推薦):單獨開個.ts文件引入pinia

在根目錄下新建文件夾,這裡我命名為store,再在文件夾下新建一個index.ts文件(src/store/index.ts),用以配置和引入pinia。

// 1-創建一個 pinia(根存儲)
import { createPinia } from 'pinia'

// 2-定義pinia實例
const pinia = createPinia();

// 3-暴露pinia實例
export default pinia;

然後在src/main.ts 中使用。

......
import pinia from '@/store/index.ts'
app.use(pinia);
......

其實和方式一沒啥區別,只是為了保持main.ts文件整潔,並且方便配置pinia。

2-創建倉庫

pinia與vuex差不多,相比於vuex,少了mutationmodules

pinia創建倉庫,有選項式寫法組合式寫法

選項式Options API寫法

在根目錄下創建一個文件夾store (src/store),在store文件夾中可以創建你的倉庫,比如下麵我創建了一個名為user的倉庫 (src/store/user.ts)。

// 選項式寫法
// 1-引入api
import { defineStore } from "pinia";

// 2-定義倉庫
const store = defineStore('user', {
    // 3-設置組件共用的狀態,相當於組件的data
    state: () => ({
        userInfo: {
            name: '老劉',
            sex: '男',
            age: 17,
            isStudent: false
        },
        token: '5201314',
        password: '123456',
    }),
    // 3-設置狀態計算值,相當於組件的computed
    getters: {
        name: (state) => state.userInfo.name,
        sex: (state) => state.userInfo.sex,
    },
    // 3-設置組件共用的方法,相當於組件的methods
    actions: {
        addAge() {
            this.userInfo.age++;
        }
    }
});

// 最後別忘了把倉庫暴露出去哦
export default store;

組合式Composition API寫法(推薦)

上面的倉庫 (src/store/user.ts)組合式寫法如下:

// 組合式寫法
// 1-引入pinia的api
import { defineStore } from "pinia";
// 2-引入vue3相關api
import { ref, reactive, computed } from 'vue';

// 3-定義倉庫,註意第二個參數需要傳入一個函數,函數需要返回一個對象!
const store = defineStore('user', () => {
    // 4-在這裡面可以像在組件中一樣,使用vue3的API,定義響應式數據
    const userInfo = reactive({
        name: '老劉',
        sex: '男',
        age: 17,
        isStudent: false
    });
    const token = ref('5201314');
    const password = ref('123456');

    // 這裡computed的作用相當於getters
    const name = computed(() => userInfo.name);
    const sex = computed(() => userInfo.sex);

    // 4-還可以定義方法
    function addAge() {
        userInfo.age++;
    }

    // 5-然後把需要共用的數據或方法,裝進一個對象,return出去
    return {
        userInfo,
        token,
        password,
        name,
        sex,
        addAge
    }
});

// 最後別忘了把倉庫暴露出去哦
export default store;

TIP

還可以在倉庫中使用watchwatchEffect等vue3的API喔~。

import { ref, reactive, computed, watch } from 'vue';
const store = defineStore('user', () => {
    const userInfo = reactive({
        age: 17,
    });
    // 使用vue3的watch()函數,可以對倉庫狀態進行監聽
    watch(() => userInfo.age, (val) => {
        console.log(val);
    });
});

3-使用pinia

完成了上面的工作後,我們就可以在組件中愉快地使用pinia啦!

下麵以src/App.vue作為示例。

(1)引入倉庫

<template>

</template>

<script setup lang="ts">
// 1-引入剛剛自定義的倉庫,模塊名store 可以自定義
import store from '@/store/user.ts';

// 2-使用倉庫,倉庫實例名userStore 可以自定義
const userStore = store();
</script>

(2)在組件中訪問倉庫stategetters

在模板和script中,state和getters可以看作倉庫實例(如userStore)的屬性,直接加.訪問即可。

<template>
    <div>
        <!-- 1-訪問倉庫的計算屬性getters -->
        <span>姓名:{{ userStore.name }}</span>
        <span>性別:{{ userStore.sex }}</span>
        <!-- 1-訪問倉庫的狀態state -->
        <span>年齡:{{ userStore.userInfo.age }}</span>
        <span>是否學生:{{ userStore.userInfo.isStudent ? '是' : '否' }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();

// 1-訪問state和getters,類似於reactive響應式數據的訪問
console.log('userStore', userStore);
console.log('姓名:', userStore.name);
console.log('性別:', userStore.sex);
console.log('年齡:', userStore.userInfo.age);
console.log('是否學生:', userStore.userInfo.isStudent ? '是' : '否');
</script>
輸出
    userStore Proxy(Object) {$id: 'user', $onAction: ƒ, $patch: ƒ, $reset: ƒ, $subscribe: ƒ, …}[[Handler]]: Object[[Target]]: Object[[IsRevoked]]: false
    
    姓名: 老劉
    性別: 男
    年齡: 17
    是否學生: 否

(3)在組件中使用倉庫actions

使用倉庫方法與訪問倉庫state類似,倉庫實例後直接加.調用即可。

<template>
    <div>
        <!-- 按鈕點擊,年齡+1 -->
        <button @click="onAddAge">年齡+1</button>
        <span>年齡:{{ userStore.userInfo.age }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();

// 按鈕點擊觸發
function onAddAge() {
    // 1-使用倉庫的actions
    userStore.addAge();
}
</script>

(4)修改state

直接修改

與vuex不同,pinia支持在組件中直接修改state

<template>
    <div>
        <!-- 按鈕點擊,年齡+1 -->
        <button @click="onAddAge">年齡+1</button>
        <span>年齡:{{ userStore.userInfo.age }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();

// 按鈕點擊觸發
function onAddAge() {
    // 1-直接修改state
    userStore.userInfo.age++;
}
</script>

利用倉庫actions進行修改

src/store/user.ts

......

const store = defineStore('user', () => {
    ......

    // 1-定義方法
    function addAge() {
        userInfo.age++;
    }

    // 2-return出去
    return {
        addAge
    }
});

// 3-導出倉庫
export default store;

src/App.vue

<template>
    <div>
        <!-- 按鈕點擊,年齡+1 -->
        <button @click="onAddAge">年齡+1</button>
        <span>年齡:{{ userStore.userInfo.age }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();

// 按鈕點擊觸發
function onAddAge() {
    // 4-使用倉庫的方法
    userStore.addAge();
}
</script>

批量變更

通過倉庫實例(如userStore)的 $patch 方法,可以對state同時應用多個更改。

<script setup lang="ts">
......

function changeState() {
    console.log(userStore.token); // '5201314'
    console.log(userStore.password); // '123456'

    // $patch()接收一個對象,對象內的屬性是 需要變更的state
    // 註意是變更,新增state是無效的!
    userStore.$patch({
        token: '1024',
        password: '654321'
    });

    console.log(userStore.token); // '1024'
    console.log(userStore.password); // '654321'
}
</script>

上面的方法每次進行批量修改都需要傳入一個新對象,有時候使用起來並不方便。下麵是另一種寫法,$patch接受一個函數來批量修改集合內部分對象。(推薦)

<script setup lang="ts">
......

function changeState() {
    // 這裡的any是typescript的類型標註,可以不用理會
    // 回調函數的參數state就是 倉庫目前的state
    userStore.$patch((state: any) => {
        state.token = '1024';
        state.password = '654321';
    });
}
</script>

整體替換(不推薦

通過倉庫實例(如userStore)的 $state 屬性,來為新對象替換倉庫的整個狀態。

pinia官網提到整體替換state的方法,但並未說明是否保留數據響應式。經筆者實踐,這種方法會丟失數據的響應式,所以不推薦使用

<script setup lang="ts">
......

function updateStore() {
    userStore.$state = {
        userInfo: {
            name: '老王',
            sex: '男',
            age: 66,
            isStudent: false
        }
    };
}
</script>

(5)重置state

通過調用倉庫實例上的 $reset() 方法將狀態重置到其初始值。

<script setup lang="ts">
......

function resetStore() {
    userStore.$reset();
}
</script>

$reset() 的坑

細心的你會發現,倉庫state並沒有重置,然後你打開你的的控制台,你會驚訝地發現它報了這麼一個錯誤:

這時候請你不要慌,先冷靜地看一下報錯信息。

這裡翻譯一下:Store "user"是使用setup語法構建的,不實現$reset()。(猜測是pinia的缺陷)

所以,根據報錯信息,這裡提供下麵兩種解決方案。

使用選項式Options API

使用選項式Options API編寫pinia倉庫,並且在組件中不能用script setup語法,要使用setup函數進行開發。

src/store/user.ts

......

// 使用選項式Options API編寫倉庫
const store = defineStore('user', {
    // 3-設置組件共用的狀態,相當於組件的data
    state: () => ({
        userInfo: {
            name: '老劉',
            sex: '男',
            age: 17,
            isStudent: false
        },
        token: '5201314',
        password: '123456',
    }),
});

export default store;

src/App.vue

<!-- 這裡不能用script setup,否則依然報錯 -->
<script lang="ts">
import store from '@/store/user.ts';

export default {
    setup() {
        const userStore = store();

        function resetStore() {
            // 重置state
            userStore.$reset();
        }

        // 把響應式數據或方法return出去
        return {
            userStore,
            resetStore
        }
    },
}
</script>

重寫一個$reset()方法(推薦)

原理:自定義pinia插件(Plugins),利用$patch() 重置整個state

在之前創建的pinia配置文件中修改(src/store/index.ts)。

import { createPinia } from 'pinia';
const pinia = createPinia();

// 1-使用pinia自定義插件
pinia.use(({ store }) => {
    // 2-獲取最開始的State
    const initialState = JSON.parse(JSON.stringify(store.$state));
    // 3-重寫$reset()方法
    store.$reset = () => {
        // 4-利用$patch()批量變更state,達到重置state的目的
        store.$patch(initialState);
    }
});

export default pinia;

推薦使用這種方法,這樣就可以在script setup中愉快地使用pinia啦!

完整示例

倉庫配置

src/store/index.ts

import { createPinia } from 'pinia';
const pinia = createPinia();

pinia.use(({ store }) => {
    const initialState = JSON.parse(JSON.stringify(store.$state));
    store.$reset = () => {
        store.$patch(initialState);
    }
});

export default pinia;

定義倉庫

src/store/user.ts

// 組合式寫法
import { defineStore } from "pinia";
import { ref, reactive, computed, watch } from 'vue';

const store = defineStore('user', () => {
    const userInfo = reactive({
        name: '老劉',
        sex: '男',
        age: 17,
        isStudent: false
    });
    const token = ref('5201314');
    const password = ref('123456');

    const name = computed(() => userInfo.name);
    const sex = computed(() => userInfo.sex);

    watch(() => userInfo.age, (val) => {
        console.log(val);
    });

    function addAge() {
        userInfo.age++;
    }

    return {
        userInfo,
        token,
        password,
        name,
        sex,
        addAge
    }
});

export default store;

父組件

src/App.vue

<template>
    <div>
        <button @click="resetStore">重置store</button>
        <h1>我是父組件</h1>
        <button @click="userStore.userInfo.age++">年齡+1</button>
        <span class="marginLeft60">姓名:{{ userStore.name }}</span>
        <span class="marginLeft60">性別:{{ userStore.sex }}</span>
        <span class="marginLeft60 red">年齡:{{ userStore.userInfo.age }}</span>
        <span class="marginLeft60 red">是否學生:{{ userStore.userInfo.isStudent ? '是' : '否' }}</span>
        <hr>

        <!-- 使用子組件A -->
        <son-a />
        <hr>

        <!-- 使用子組件B -->
        <son-b />
        <hr>
    </div>
</template>

<script setup lang="ts">
// 引入子組件
import SonA from './components/sonA.vue';
import SonB from './components/sonB.vue';

// 1-引入倉庫
import store from '@/store/user.ts';

// 2-使用倉庫
const userStore = store();

// 重置store
function resetStore() {
    userStore.$reset();
}
</script>

<style>
.marginLeft60 {
    margin-left: 60px;
}

.red {
    color: red;
}
</style>

子組件A

src/components/sonA.vue

<template>
    <div>
        <h2>我是子組件A</h2>
        <button @click="userStore.userInfo.isStudent = true">入學</button>
        <span class="marginLeft60">姓名:{{ userStore.name }}</span>
        <span class="marginLeft60">性別:{{ userStore.sex }}</span>
        <span class="marginLeft60 red">年齡:{{ userStore.userInfo.age }}</span>
        <span class="marginLeft60 red">是否學生:{{ userStore.userInfo.isStudent ? '是' : '否' }}</span>
        <grandson />
    </div>
</template>

<script setup lang="ts">
import Grandson from './grandson.vue';
import store from '@/store/user.ts';

const userStore = store();
</script>

子組件B

src/components/sonB.vue

<template>
    <div>
        <h2>我是子組件B</h2>
        <button @click="userStore.userInfo.isStudent = false">畢業</button>
        <span class="marginLeft60">姓名:{{ userStore.name }}</span>
        <span class="marginLeft60">性別:{{ userStore.sex }}</span>
        <span class="marginLeft60 red">年齡:{{ userStore.userInfo.age }}</span>
        <span class="marginLeft60 red">是否學生:{{ userStore.userInfo.isStudent ? '是' : '否' }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();
</script>

孫組件

src/components/grandson.vue

<template>
    <div>
        <h3>我是孫組件</h3>
        <span class="marginLeft60">姓名:{{ userStore.name }}</span>
        <span class="marginLeft60">性別:{{ userStore.sex }}</span>
        <span class="marginLeft60 red">年齡:{{ userStore.userInfo.age }}</span>
        <span class="marginLeft60 red">是否學生:{{ userStore.userInfo.isStudent ? '是' : '否' }}</span>
    </div>
</template>

<script setup lang="ts">
import store from '@/store/user.ts';
const userStore = store();
</script>

效果圖


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 下麵的系列文章記錄瞭如何使用一塊linux開發扳和一塊OLED屏幕實現視頻的播放: 項目介紹 為OLED屏幕開發I2C驅動 使用cuda編程加速視頻處理 這篇文章主要對項目的實現做整體的介紹, 包括硬體的需求, 最終實現的視頻播放效果, 以及軟體的實現思路. 1). 硬體需求 beaglebone ...
  • 對於有科班背景的讀者,可以跳過本系列文章。這些文章的主要目的是通過簡單易懂的彙總,幫助非科班出身的讀者理解底層知識,進一步瞭解為什麼在面試中會涉及這些底層問題。否則,某些概念將始終無法理解。這些電腦基礎文章將為你打通知識的任督二脈,祝你在編程領域中取得成功! ...
  • 下麵的系列文章記錄瞭如何使用一塊linux開發扳和一塊OLED屏幕實現視頻的播放: 項目介紹 為OLED屏幕開發I2C驅動 使用cuda編程加速視頻處理 這是此系列文章的第2篇, 主要總結和記錄一個I2C從設備的驅動, 在linux內核中如何實現, 如何給用戶態的程式暴露合適的介面, 讓用戶態有機會 ...
  • 1. 除非遇到異常情況,否則不需要調整配置 1.1. 不要“調優”伺服器,不要使用比率、公式或“調優腳本”作為設置配置變數的基礎 1.1.1. 在互聯網上搜索配置建議並不總是一個好主意,你會在博客、論壇等找到很多糟糕的建議 1.1.2. 很難判斷誰是真正的專家 1.1.3. 不要相信流行的記憶體消耗公 ...
  • Flink是一個分散式系統,要求有效地分配和管理計算資源以執行流式應用程式。它集成了所有常見的集群資源管理器,如Hadoop YARN和Kubernetes,但也可以設置為作為standalone甚至庫運行。 本節概述了Flink的體繫結構,並描述了其主要組件如何交互以執行應用程式以及從故障中恢復。 ...
  • 1. mysql資料庫四種常見資料庫引擎 1. MyISAM: MyISAM是MySQL最早的資料庫引擎之一。它被設計成處理大量的插入和查詢操作。MyISAM表格的數據存儲在三個文件上:.frm文件存儲表結構,.MYD文件存儲數據,.MYI文件存儲索引。MyISAM表格不支持事務處理和崩潰恢復,因此 ...
  • 隨著需求的不斷開發,前端項目不斷膨脹,業務提出:你們的首頁載入也太慢啦,我都需要7、8秒才能看到內容,於是乎主管就讓我聯合後端開啟優化專項,目標是3s內展示完全首頁的內容。 性能指標 開啟優化時,我們要清晰的知道現狀和目標,以及我們採用什麼樣的手段,通過檢測什麼指標來查看到優化的過程。 結果指標 根 ...
  • 功能介紹 登錄 首頁 修改密碼 提交申請 提交列表 數據可視化 審核列表 前端 components結構 搭建Vue項目 ​ Vue3快速上手: ​ https://cn.vuejs.org/guide/quick-start.html#creating-a-vue-application 頁面佈局 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...