Общее состояние: useState
Иногда одни и те же данные нужны в разных частях сайта: имя вошедшего пользователя показывается и в шапке, и на странице профиля. useState создаёт такое общее значение по ключу. Все компоненты, которые обращаются к одному ключу, получают один и тот же реактивный ref.
Минимальный пример
<!-- app/pages/index.vue -->
<script setup lang="ts">
const visits = useState('visits', () => 0)
</script>
<template>
<section>
<h2>Главная</h2>
<button @click="visits++">Нажато: {{ visits }}</button>
</section>
</template>Первый аргумент — ключ, второй — функция, которая задаёт начальное значение. Нажмите кнопку несколько раз, перейдите на /about и вернитесь — счётчик сохранит значение, ведь он хранится вне компонента.
Composable с общим состоянием
Ключ удобно спрятать в composable, чтобы не повторять его в каждом файле. Создайте app/composables/useCurrentUser.ts:
// app/composables/useCurrentUser.ts
export function useCurrentUser() {
return useState<string | null>('current-user', () => null)
}Тип в угловых скобках говорит, что значение — строка или null, если никто не вошёл.
Использование в двух местах
Шапка в макете показывает имя:
<!-- app/layouts/default.vue -->
<script setup lang="ts">
const user = useCurrentUser()
</script>
<template>
<div>
<header>
<NuxtLink to="/">Главная</NuxtLink>
<span v-if="user">Привет, {{ user }}</span>
<NuxtLink v-else to="/login">Войти</NuxtLink>
</header>
<slot />
</div>
</template>А страница входа его меняет:
<!-- app/pages/login.vue -->
<script setup lang="ts">
const user = useCurrentUser()
const name = ref('')
function login() {
user.value = name.value
navigateTo('/')
}
</script>
<template>
<form @submit.prevent="login">
<input v-model="name" placeholder="Ваше имя">
<button>Войти</button>
</form>
</template>Введите на /login имя «Анна» и нажмите «Войти»: в шапке появится «Привет, Анна». Это пока не настоящий вход — после перезагрузки страницы имя пропадёт. Вход с проверкой пароля разобран в уроке об аутентификации.
Почему не обычный ref
| Способ | Что происходит |
|---|---|
ref внутри компонента | Своё значение у каждого компонента |
ref в файле вне функции | На сервере одно значение на всех посетителей |
useState | Отдельное значение для каждого запроса, переходит с сервера в браузер |
Значение, заданное на сервере, Nuxt передаёт в браузер вместе с HTML, поэтому после гидратации оно не теряется.
Частая ошибка
Объявить общее состояние так: export const user = ref(null) в отдельном файле. В браузере это работает, но на сервере такой ref один на всех посетителей сразу: имя, сохранённое во время запроса Анны, увидит и Олег. Для общих данных используйте useState или Pinia. И храните в useState только простые данные — строки, числа, массивы и объекты, но не функции и не экземпляры классов: их нельзя передать в браузер.