透過超過 100 個技巧的集合來學習 Nuxt!

狀態管理

Nuxt 提供了強大的狀態管理函式庫和 useState composable 來建立響應式且伺服器端渲染友好的共享狀態。

Nuxt 提供了 useState composable,以便在組件之間建立響應式且伺服器端渲染友好的共享狀態。

useState 是伺服器端渲染友好的 ref 替代方案。它的值將在伺服器端渲染後(在客戶端 hydration 期間)保留,並在使用唯一鍵的所有組件之間共享。

觀看 Alexander Lichter 關於為什麼以及何時使用 useState() 的影片。
由於 useState 內部的資料將序列化為 JSON,因此重要的是它不包含任何無法序列化的內容,例如類別、函式或符號。
閱讀更多關於 useState composable 的資訊。

最佳實務

切勿在 <script setup>setup() 函式之外定義 const state = ref()
例如,執行 export myState = ref({}) 會導致在伺服器上跨請求共享狀態,並可能導致記憶體洩漏。
請改用 const useX = () => useState('x')

範例

基本用法

在此範例中,我們使用組件本地的計數器狀態。任何其他使用 useState('counter') 的組件都會共享相同的響應式狀態。

app.vue
<script setup lang="ts">
const 
counter
=
useState
('counter', () =>
Math
.
round
(
Math
.
random
() * 1000))
</script> <template> <
div
>
Counter: {{
counter
}}
<
button
@
click
="
counter
++">
+ </
button
>
<
button
@
click
="
counter
--">
- </
button
>
</
div
>
</template>
文件 > 範例 > 功能 > 狀態管理 中閱讀並編輯即時範例。
要全域使快取狀態失效,請參閱 clearNuxtState util。

初始化狀態

大多數情況下,您會希望使用非同步解析的資料來初始化狀態。您可以使用帶有 callOnce util 的 app.vue 組件來執行此操作。

app.vue
<script setup lang="ts">
const 
websiteConfig
=
useState
('config')
await
callOnce
(async () => {
websiteConfig
.
value
= await
$fetch
('https://my-cms.com/api/website-config')
}) </script>
這類似於 Nuxt 2 中的 nuxtServerInit action,它允許在渲染頁面之前在伺服器端填入您的 store 的初始狀態。
詳情請參閱文件 > API > 工具 > 單次呼叫

搭配 Pinia 使用

在這個範例中,我們利用 Pinia 模組建立一個全域 store,並在整個應用程式中使用。

請務必使用 npx nuxi@latest module add pinia 安裝 Pinia 模組,或依照模組的安裝步驟進行安裝。
export const useWebsiteStore = defineStore('websiteStore', {
  state: () => ({
    name: '',
    description: ''
  }),
  actions: {
    async fetch() {
      const infos = await $fetch('https://api.nuxt.com/modules/pinia')

      this.name = infos.name
      this.description = infos.description
    }
  }
})

進階用法

import type { Ref } from 'vue'

export const useLocale = () => {
  return useState<string>('locale', () => useDefaultLocale().value)
}

export const useDefaultLocale = (fallback = 'en-US') => {
  const locale = ref(fallback)
  if (import.meta.server) {
    const reqLocale = useRequestHeaders()['accept-language']?.split(',')[0]
    if (reqLocale) {
      locale.value = reqLocale
    }
  } else if (import.meta.client) {
    const navLang = navigator.language
    if (navLang) {
      locale.value = navLang
    }
  }
  return locale
}

export const useLocales = () => {
  const locale = useLocale()
  const locales = ref([
    'en-US',
    'en-GB',
    ...
    'ja-JP-u-ca-japanese'
  ])
  if (!locales.value.includes(locale.value)) {
    locales.value.unshift(locale.value)
  }
  return locales
}

export const useLocaleDate = (date: Ref<Date> | Date, locale = useLocale()) => {
  return computed(() => new Intl.DateTimeFormat(locale.value, { dateStyle: 'full' }).format(unref(date)))
}
文件 > 範例 > 進階 > Locale 中閱讀並編輯即時範例。

共享狀態

透過使用自動匯入的 composables,我們可以定義全域型別安全的狀態,並在整個應用程式中匯入它們。

composables/states.ts
export const 
useColor
= () =>
useState
<string>('color', () => 'pink')
app.vue
<script setup lang="ts">
// ---cut-start---
const useColor = () => useState<string>('color', () => 'pink')
// ---cut-end---
const color = useColor() // Same as useState('color')
</script>

<template>
  <p>Current color: {{ color }}</p>
</template>
觀看 Daniel Roe 的影片,了解如何在 Nuxt 中處理全域狀態和 SSR。

使用第三方函式庫

Nuxt 過去依賴 Vuex 函式庫來提供全域狀態管理。如果您是從 Nuxt 2 遷移而來,請前往遷移指南

Nuxt 對於狀態管理沒有既定的偏好,因此您可以自由選擇適合您需求的解決方案。有多個與最流行的狀態管理函式庫的整合,包括:

  • Pinia - Vue 的官方推薦
  • Harlem - 不可變的全域狀態管理
  • XState - 狀態機方法,提供視覺化和測試狀態邏輯的工具