Олег Марков
Работа с данными в Nuxt с помощью useNuxtData
Введение
Когда вы работаете над современным веб-приложением, задача получения и управления асинхронными данными часто выходит на первый план. В Nuxt для загрузки данных есть useFetch и useAsyncData, а рядом с ними — небольшая, но очень полезная composable-функция useNuxtData. Её часто понимают неправильно, поэтому давайте сразу расставим точки над i.
useNuxtData ничего не загружает. Она даёт вам доступ к данным, которые уже лежат в кеше Nuxt — то есть к результату более раннего вызова useFetch или useAsyncData с тем же ключом. Это синхронная функция: её не нужно вызывать через await, и она не возвращает ни pending, ни error, ни refresh.
Звучит скромно, но именно на этом строятся два очень практичных приёма: мгновенное отображение данных при переходе между страницами и оптимистичные обновления интерфейса. Их мы и разберём.
Все примеры в статье написаны для Nuxt 3 и Nuxt 4 — API
useNuxtDataв этих версиях одинаков. В Nuxt 2 этой функции нет.
Эффективное получение и передача данных - это основа для создания динамичных и интерактивных Nuxt-приложений. Но для оптимизации этого процесса необходимо понимать, как работают различные методы получения данных, как кэшировать запросы и как обрабатывать большие объемы данных. Если вы хотите узнать больше о способах получения и передачи данных в Nuxt, приходите на наш большой курс Nuxt - fullstack Vue фреймворк. На курсе 129 уроков и 13 упражнений, AI-тренажеры для безлимитной практики с кодом и задачами 24/7, решение задач с живым ревью наставника, еженедельные встречи с менторами.
Хотите разобраться глубже? Пройдите Курс Nuxt с нуля — практика, наставники, реальные проекты.
Курс по теме
Курс Nuxt с нуля
40 000+ студентов · рейтинг 4.8 · гарантия возврата 30 дней
Что такое useNuxtData
useNuxtData — это composable-функция Nuxt, которая возвращает реактивную ссылку на данные, сохранённые в payload приложения под указанным ключом.
// Единственный аргумент — ключ, под которым данные были закешированы
const { data } = useNuxtData('users')
Разберём, что здесь происходит:
'users'— ключ кеша. Тот же самый ключ, который вы передали вuseFetchилиuseAsyncData;data— этоRef. Если под таким ключом уже есть данные, вы получите их сразу; если нет — внутри будетnull;- вызов синхронный.
await useNuxtData(...)писать не нужно — там нечего ждать.
Обратите внимание на важное следствие: если никто ещё не загружал данные под этим ключом, data.value будет null, и это нормальная штатная ситуация, которую нужно обрабатывать.
Откуда в кеше берутся данные
Кеш заполняют функции загрузки. Ключ можно задать явно:
// Явный ключ — так вы точно знаете, по какому имени данные окажутся в кеше
const { data: users } = await useFetch('/api/users', { key: 'users' })
Если ключ не указать, Nuxt сгенерирует его автоматически на основе места вызова. Такой ключ непредсказуем, поэтому для работы с useNuxtData всегда задавайте ключ явно.
Чем useNuxtData отличается от useFetch и useAsyncData
Это разные инструменты, а не альтернативы друг другу:
| Загружает данные | Возвращает | Нужен await | |
|---|---|---|---|
useFetch | да, делает HTTP-запрос | data, status, error, refresh, clear | да |
useAsyncData | да, выполняет вашу функцию | data, status, error, refresh, clear | да |
useNuxtData | нет, только читает кеш | data | нет |
То есть useNuxtData не заменяет загрузку данных — она работает поверх уже загруженных данных.
Сценарий 1: мгновенный показ данных при переходе на страницу
Это самый частый и самый выигрышный сценарий. Представьте список постов и страницу отдельного поста. Когда пользователь кликает по посту из списка, заголовок и краткое описание у нас уже есть — они лежат в кеше списка. Значит, можно показать их немедленно, не заставляя пользователя смотреть на спиннер.
Сначала страница со списком — здесь мы задаём ключ явно:
<!-- pages/posts.vue -->
<script setup>
// Ключ 'posts' пригодится нам на странице отдельного поста
const { data: posts } = await useFetch('/api/posts', { key: 'posts' })
</script>
<template>
<ul>
<li v-for="post in posts" :key="post.id">
<NuxtLink :to="`/posts/${post.id}`">{{ post.title }}</NuxtLink>
</li>
</ul>
</template>
Теперь страница поста. Смотрите, как здесь используется кеш:
<!-- pages/posts/[id].vue -->
<script setup>
const route = useRoute()
const id = route.params.id
// Достаём из кеша список, загруженный на предыдущей странице
const { data: posts } = useNuxtData('posts')
const { data: post } = await useFetch(`/api/posts/${id}`, {
key: `post-${id}`,
// Пока идёт запрос, показываем данные из кеша списка
default() {
return posts.value?.find((p) => p.id === Number(id))
}
})
</script>
<template>
<article v-if="post">
<h1>{{ post.title }}</h1>
<p>{{ post.body }}</p>
</article>
</template>
Что мы получили: пользователь видит заголовок поста сразу при переходе, а полный текст подставляется, когда приходит ответ сервера. Если же пользователь открыл страницу поста напрямую по ссылке, кеш будет пуст, default() вернёт undefined, и страница просто отрисуется после загрузки — никакой ошибки не произойдёт.
Сценарий 2: оптимистичные обновления
Второй сценарий — когда вы хотите обновить интерфейс до того, как сервер подтвердит изменение. Пользователь добавил задачу — она сразу появилась в списке; если сервер вернул ошибку, откатываем изменение назад.
<script setup>
// Читаем тот же список, что загружен через useFetch с ключом 'todos'
const { data: todos } = useNuxtData('todos')
async function addTodo(todo) {
// Сохраняем предыдущее состояние, чтобы было к чему откатиться
const previous = todos.value ? [...todos.value] : []
// Обновляем UI немедленно
todos.value = [...previous, todo]
try {
await $fetch('/api/todos', { method: 'POST', body: todo })
} catch (error) {
// Запрос не прошёл — возвращаем список в исходное состояние
todos.value = previous
} finally {
// В любом случае синхронизируемся с сервером
await refreshNuxtData('todos')
}
}
</script>
Здесь todos.value = ... меняет именно тот Ref, который вернул useFetch на другой странице или в другом компоненте — данные в кеше общие. Поэтому изменение подхватят все места, где этот ключ используется.
Как обновлять и очищать кеш
У самой useNuxtData нет метода refresh — обновлением занимаются отдельные утилиты Nuxt.
refreshNuxtData
Перезапускает загрузку для указанного ключа (или для всех ключей, если вызвать без аргументов):
// Перезагрузить данные под конкретным ключом
await refreshNuxtData('todos')
// Перезагрузить сразу несколько ключей
await refreshNuxtData(['todos', 'users'])
clearNuxtData
Удаляет данные из кеша, не запуская загрузку заново:
// Данные под ключом 'todos' будут сброшены в null
clearNuxtData('todos')
Это удобно при выходе пользователя из аккаунта, когда закешированные данные больше показывать нельзя.
refresh из useFetch
Если вы находитесь в том же компоненте, где вызывали useFetch, проще воспользоваться его собственным refresh:
const { data, refresh } = await useFetch('/api/todos', { key: 'todos' })
// Кнопку «Обновить» вешаем прямо на refresh
Статусы загрузки и ошибки
Раз useNuxtData не загружает данные, у неё нет и статусов загрузки. Индикатор загрузки и ошибку берите из той функции, которая данные загружает:
<script setup>
// status и error приходят из useFetch, а не из useNuxtData
const { data: todos, status, error, refresh } = await useFetch('/api/todos', {
key: 'todos'
})
</script>
<template>
<div v-if="status === 'pending'">Загрузка...</div>
<div v-else-if="error">Ошибка: {{ error.message }}</div>
<ul v-else>
<li v-for="todo in todos" :key="todo.id">{{ todo.title }}</li>
</ul>
<button @click="refresh" :disabled="status === 'pending'">Обновить</button>
</template>
Важный момент, о который часто спотыкаются: если вы написали await useFetch(...), то к моменту следующей строки загрузка уже завершена. Проверять status сразу после await в скрипте бессмысленно — он никогда не будет 'pending'. Индикатор загрузки имеет смысл только в шаблоне, где он реагирует на реактивные изменения, либо при вызове useFetch без await (например, с опцией lazy: true).
Типизация
useNuxtData принимает тип-параметр, поэтому вы можете описать форму данных:
interface Todo {
id: number
title: string
done: boolean
}
// data будет иметь тип Ref<Todo[] | null>
const { data: todos } = useNuxtData<Todo[]>('todos')
Значение null в типе — не случайность: оно напоминает, что кеш может быть пуст, и это нужно обработать.
Практические советы
- Всегда задавайте ключ явно в
useFetchиuseAsyncData— без этого вы не сможете достучаться до данных черезuseNuxtData. - Используйте осмысленные префиксы в ключах —
post-42вместо42,user-profile-42вместоprofile. Это защищает от коллизий. - Не пишите
awaitпередuseNuxtData— функция синхронная, иawaitтолько запутает читателя кода. - Всегда проверяйте
data.valueнаnull— кеш может быть пуст, если пользователь открыл страницу напрямую. - Для обновления используйте
refreshNuxtData, а для полной очистки —clearNuxtData.
Заключение
useNuxtData — это небольшой, но точный инструмент: доступ к уже загруженным данным по ключу. Она не делает запросов и не управляет их жизненным циклом — за это отвечают useFetch и useAsyncData. Зато она позволяет переиспользовать данные между страницами и компонентами, показывать пользователю содержимое мгновенно и делать оптимистичные обновления с честным откатом при ошибке.
Работа с данными - это один из ключевых аспектов веб-разработки. Чтобы создавать гибкие и масштабируемые приложения, необходимо освоить все возможности фреймворка, включая работу с сервером, базами данных и API. На нашем курсе Nuxt - fullstack Vue фреймворк вы найдете все необходимые знания и навыки для достижения успеха. В первых 3 модулях уже доступно бесплатное содержание — начните погружаться в Nuxt прямо сегодня.
Частозадаваемые технические вопросы по теме статьи и ответы на них
Почему useNuxtData возвращает null?
Значит, под этим ключом в кеше ничего нет. Самые частые причины: данные ещё не загружались (пользователь открыл страницу напрямую), в useFetch не был задан ключ явно, либо ключи не совпадают по написанию. Проверьте, что в обоих местах используется одна и та же строка.
Как обновить данные, если useNuxtData не возвращает refresh?
Используйте refreshNuxtData('ключ') — эта утилита доступна глобально и перезапускает загрузку для указанного ключа. Если вы находитесь в компоненте, где вызывался useFetch, берите refresh прямо из его результата.
Можно ли использовать useNuxtData в middleware или плагине?
Да, вызывать её можно. Но помните, что она только читает кеш: если данные ещё не загружены, вы получите null. Для загрузки данных в middleware используйте useAsyncData или $fetch.
Что делать, если данные зависят от параметров маршрута?
Включите параметр в ключ при загрузке, а затем читайте по тому же ключу:
const route = useRoute()
const { data } = await useFetch(`/api/user/${route.params.id}`, {
key: `user-${route.params.id}`
})
// В другом компоненте
const { data: user } = useNuxtData(`user-${route.params.id}`)
Как очистить кеш при выходе пользователя из аккаунта?
Вызовите clearNuxtData со списком ключей, которые относятся к пользовательским данным:
clearNuxtData(['user-profile', 'todos', 'notifications'])
Данные под этими ключами станут null, и при следующем запросе будут загружены заново.
Постройте личный план изучения Nuxt до уровня Middle — бесплатно!
Nuxt — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Nuxt
Лучшие курсы по теме

Nuxt
Антон Ларичев
TypeScript с нуля
Антон Ларичев