通过 100 多个技巧学习 Nuxt!

状态管理

Nuxt 提供了强大的状态管理库和 useState composable,用于创建响应式且对 SSR 友好的共享状态。

Nuxt 提供了 useState composable,用于在组件之间创建响应式且对 SSR 友好的共享状态。

useState 是一个对 SSR 友好的 ref 替代品。它的值在服务器端渲染(在客户端水合期间)后将被保留,并在使用唯一键的所有组件之间共享。

观看 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。

初始化状态

大多数情况下,你希望使用异步解析的数据来初始化你的状态。你可以使用 app.vue 组件,并结合 callOnce 工具来实现。

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 > 工具 > Call Once 中阅读更多信息。

与 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)))
}
文档 > 示例 > 高级 > 本地化 中阅读和编辑一个实时示例。

共享状态

通过使用自动导入的 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 - 使用可视化和测试状态逻辑的工具的状态机方法