Nuxt 3 開發心得 — 比較 Pinia、useState

Monster0313
5 min readDec 12, 2023

--

Photo by Hunter Harritt on Unsplash

最近陸續接觸到了 Nuxt 3 的專案,不可避免地在開發時遇到了必須在多個 Component 之間傳遞資料的需求,這篇文章將會簡單介紹在 Nuxt 3 最常使用到的 2 種跨元件資料傳遞方式。

Pinia

不論是官方文件或是各種教學文章,一定會提到在 Nuxt 3 如果要使用 Pinia 作為跨元件的儲存套件,這邊我就不贅述安裝設定之類的步驟了,僅會提出用法與一些注意事項。

這裡,我們會以購物車作為範例。

定義一個 Store

我們需要先使用 defineStore() 定義一個 Store,而這一個定義的 Store 就跟命名變數一樣,需要替它命一個具有唯一性的名字。

// 範例:購物車的 Store
export const useCartStore = defineStore('storeCart', () => {
// 這裡放購物車的商品
}

設定 State

當我們定義完成 Store 後,接著來放一些資料吧

// 範例:購物車的 Store
export const useCartStore = defineStore('storeCart', () => {
// 這裡放購物車的商品
const product = ref([])

return {
product
}
}

設定 Action

Pinia 有一個跟 Vuex 不同的地方,差異處在於 Pinia 沒有 Mutation,如果需要去改變 State 的值的時候,可以透過 Action 去實作。

// 範例:購物車的 Store
export const useCartStore = defineStore('storeCart', () => {
// 這裡放購物車的商品
const product = ref([])

// 這裡放增加商品的方法
const addProduct = (value) => {
product.value.push(value)
}

return {
product,
addProduct
}
}

useState

useState 是包含在 Nuxt 3 原生的 Composable,因此不需要再額外安裝套件即可馬上使用,而且能夠建立 SSR-friendly 的共享狀態,在部分情境下,使用 useState 會是個更好的選擇。

其實 useState 最主要用來解決的是 server-side 跟 client-side 經過 Javascript 渲染時資料不同的問題。

<template>
<div>
{{ random }}
</div>
</template>

<script setup>
const random = ref(Math.round(Math.random() * 100));
</script>

由於,HTML 的部分包含了 random 的變數,因此在 server-side 執行渲染 HTML 傳到瀏覽器的時候,會先經過一次 Math.random() 的過程,
而到 client-side 的時候載入了完整的 Javascript 此時又會再經過一次 Math.random() 的過程,此時會造成 random 的數值不相同。

這個狀況發生的時候,我們會在 console 看見錯誤警告 Hydration text content mismatch
Hydration 的中文翻譯叫「水合、補水」,字面上的意義比較艱澀,可以想像 server-side 跟 client-side 分別負責了兩件事, server-side 就是在產生模具,client-side 就是將資料、Javascript 注入這個產生好的模具中,使用這個詞來形容這個過程確實蠻生動的。

既然 useState是要用來解決 Hydration 問題的,那為什麼能夠作為共享資料的方式呢?

沒錯,就是透過搭配 Composables 來達成的。

我們可以先建立一個 complsables/useRandom.js

export const useRandom = () => {
const random = useState('random', () => Math.round(Math.random() * 100))

return {
random
}
}

而在頁面或者 component 中使用 useRandom 來取得資料

<template>
<div>
{{ random }}
</div>
</template>

<script setup>
const { random } = useRandom();
</script>

透過這種方式,就可以在全域共享狀態,同時省去擔心 Hydration 的問題。

結論心得

使用 Nuxt 3 開發的時候,跟使用 Vue 3 / Composition API 開發的時候,大多數的開發體驗是相似的,但在開發 Nuxt 3 的初期,會發現自己偶爾會碰到 Hydration 的錯誤訊息,當時並沒有非常深刻理解這個觀念,也是到後來比較有時間才有機會重新學習這個觀念。

全域狀態管理是個很方便的工具,但同時也會有一些問題衍伸,因此選擇當下最適切的作法來去處理狀態管理是個相當重要的課題。

--

--

Monster0313
Monster0313

Written by Monster0313

Before understanding technology, one must first understand the humanities.|Frontend Developer in Taiwan