\n\n\n```\n\nЭтот код автоматически кэширует результат с ключом `user-{userId}`.\n\n## Как работает кэш в useAsyncData\n\n### 1. Ключ кэша обязателен\n\n```typescript\n// ✓ ПРАВИЛЬНО: уникальный ключ кэша\nconst { data } = await useAsyncData('products-list', () => fetchProducts());\n\n// ✗ НЕПРАВИЛЬНО: нет ключа кэша\nconst { data } = await useAsyncData(null, () => fetchProducts());\n```\n\nКлюч должен быть:\n- **Уникальным** для каждого запроса\n- **Консистентным** (всегда один и тот же для одних данных)\n- **Описательным** (понимаем, что это кэш)\n\n### 2. Динамические ключи\n\n```typescript\n// Для динамических данных — включай переменные в ключ\nconst route = useRoute();\nconst userId = route.params.id;\nconst filter = route.query.filter;\n\nconst { data: user } = await useAsyncData(\n `user-${userId}-${filter}`, // включаем переменные\n () => $fetch(`/api/users/${userId}?filter=${filter}`)\n);\n\n// Причина: если меняется userId, нужен новый ключ\n// Иначе будут показаны старые кэшированные данные\n```\n\n### 3. Кэширование на сервере и клиенте\n\n```typescript\n// Nuxt 3 использует payload extraction\nconst { data, refresh } = await useAsyncData(\n 'products',\n async () => {\n return await $fetch('/api/products');\n },\n {\n server: true, // выполнить на сервере (SSR)\n // Результат попадёт в payload.json и будет переиспользован на клиенте\n }\n);\n\n// На сервере: запрос выполнится\n// На клиенте: данные возьмут из payload.json, новый запрос не будет\n```\n\n## Опции useAsyncData\n\n### 1. watch — пересчитывать при изменении\n\n```typescript\nconst userId = ref('1');\n\nconst { data: user } = await useAsyncData(\n `user-${userId.value}`,\n () => $fetch(`/api/users/${userId.value}`),\n {\n watch: [userId] // перезагрузить при изменении userId\n }\n);\n\n// Когда userId меняется:\n// 1. Nuxt видит изменение через watch\n// 2. Видит, что ключ кэша изменился (user-1 -> user-2)\n// 3. Запрашивает новые данные\n// 4. Кэширует под новым ключом\n```\n\n### 2. pick — выбрать свойства из ответа\n\n```typescript\nconst { data } = await useAsyncData(\n 'user',\n () => $fetch('/api/user'),\n {\n pick: ['id', 'name', 'email'] // кэширует только эти поля\n // остальное (address, phone) не попадёт в payload\n }\n);\n```\n\n### 3. transform — трансформировать данные\n\n```typescript\nconst { data: formattedUser } = await useAsyncData(\n 'user',\n () => $fetch('/api/user'),\n {\n transform: (data) => ({\n ...data,\n displayName: `${data.firstName} ${data.lastName}`,\n isAdmin: data.role === 'admin'\n })\n }\n);\n// Кэшируются трансформированные данные\n```\n\n### 4. dedupe — дедубликация запросов\n\n```typescript\n// Если несколько компонентов одновременно запрашивают одни данные\nconst { data: users } = await useAsyncData(\n 'users',\n () => $fetch('/api/users'),\n {\n dedupe: 'cancel' // отменить дубликаты запросов\n // вместо 3 запросов будет 1\n }\n);\n```\n\n## Управление кэшем вручную\n\n### 1. Функция refresh() — пересчитать данные\n\n```typescript\nconst { data, refresh, pending } = await useAsyncData(\n 'products',\n () => $fetch('/api/products')\n);\n\nconst handleRefresh = async () => {\n // Пересчитать данные (игнорируя кэш)\n await refresh();\n};\n```\n\n### 2. clear() — очистить кэш\n\n```typescript\nconst { clear } = await useAsyncData('products', () => fetchProducts());\n\n// Где-то в приложении\nconst handleClearCache = () => {\n clear(); // кэш удалён, следующий вызов будет запрос\n};\n```\n\n### 3. useAsyncData vs $fetch\n\n```typescript\n// useAsyncData — с кэшем и SSR\nconst { data } = await useAsyncData('products', () => $fetch('/api/products'));\n\n// $fetch — просто запрос, без кэша\nconst data = await $fetch('/api/products');\n\n// Используй useAsyncData для:\n// - Данных, которые используются в нескольких компонентах\n// - SSR (рендеринг на сервере)\n// - Кэширования результатов\n\n// Используй $fetch для:\n// - One-time запросов\n// - Отправки данных (POST, PUT)\n// - Когда кэш не нужен\n```\n\n## Практические примеры\n\n### Пример 1: Список товаров с фильтром\n\n```typescript\n\n\n\n```\n\n### Пример 2: Глобальный кэш (composable)\n\n```typescript\n// composables/useProducts.ts\nexport const useProducts = () => {\n return useAsyncData(\n 'products-list', // один ключ для всех компонентов\n () => $fetch('/api/products'),\n {\n server: true // кэширует на сервере\n }\n );\n};\n\n// components/ProductList.vue\n\n```\n\n### Пример 3: Инвалидация кэша после мутации\n\n```typescript\nconst { data: user, refresh } = await useAsyncData(\n 'current-user',\n () => $fetch('/api/user')\n);\n\nconst handleUpdateProfile = async (updates) => {\n await $fetch('/api/user', {\n method: 'PUT',\n body: updates\n });\n \n // Инвалидировать кэш и пересчитать\n await refresh();\n};\n```\n\n### Пример 4: Nested data с кэшем\n\n```typescript\n// Сложная структура данных\nconst { data } = await useAsyncData(\n 'dashboard',\n async () => {\n const [user, stats, settings] = await Promise.all([\n $fetch('/api/user'),\n $fetch('/api/stats'),\n $fetch('/api/settings')\n ]);\n \n return { user, stats, settings };\n },\n {\n pick: ['user.id', 'user.name', 'stats.totalVisits']\n // кэшируется только выбранные поля\n }\n);\n```\n\n## Сравнение с React (SWR / React Query)\n\nВ React аналогичный функционал:\n\n```typescript\n// React Query (современный стандарт)\nimport { useQuery } from '@tanstack/react-query';\n\nconst { data, isLoading, refetch } = useQuery({\n queryKey: ['user', userId], // ключ кэша\n queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),\n staleTime: 5 * 60 * 1000 // кэш свеж 5 минут\n});\n\n// SWR\nimport useSWR from 'swr';\n\nconst { data, error, mutate } = useSWR(\n userId ? `/api/users/${userId}` : null, // ключ кэша\n fetcher\n);\n```\n\n## Best Practices\n\n### 1. Ключи должны быть уникальны и описательны\n\n```typescript\n✓ useAsyncData('user-profile-123', ...)\n✓ useAsyncData('products-category-electronics', ...)\n✗ useAsyncData('data', ...) // слишком общий\n✗ useAsyncData(`${Math.random()}`, ...) // не консистентный\n```\n\n### 2. Включай переменные в ключ кэша\n\n```typescript\nconst userId = route.params.id;\n\n✓ useAsyncData(`user-${userId}`, () => fetchUser(userId))\n✗ useAsyncData('user', () => fetchUser(userId)) // ключ не меняется\n```\n\n### 3. Используй watch для реактивности\n\n```typescript\nconst filter = ref('all');\n\n✓ useAsyncData(\n () => `products-${filter.value}`,\n () => fetchProducts(filter.value),\n { watch: [filter] }\n )\n\n✗ useAsyncData(\n 'products',\n () => fetchProducts(filter.value)\n // filter меняется, но кэш не обновляется\n )\n```\n\n### 4. Инвалидируй кэш после мутаций\n\n```typescript\nconst { refresh } = await useAsyncData('user', fetchUser);\n\nconst updateUser = async (data) => {\n await postUpdate(data);\n await refresh(); // обновить кэш\n};\n```\n\n### 5. Используй pick для оптимизации payload\n\n```typescript\n// Кэшируется полный ответ API (может быть большим)\n✗ useAsyncData('user', () => $fetch('/api/user'))\n\n// Кэшируются только нужные поля\n✓ useAsyncData(\n 'user',\n () => $fetch('/api/user'),\n { pick: ['id', 'name', 'email'] }\n )\n```\n\n## Итог\n\n**Кэширование в useAsyncData**:\n\n1. **Ключ кэша** — обязательный, уникальный идентификатор\n2. **Динамические ключи** — включай переменные для разных данных\n3. **watch** — пересчитывать при изменении зависимостей\n4. **refresh()** — инвалидировать и пересчитать кэш\n5. **pick** — оптимизировать размер payload на сервере\n6. **SSR** — данные кэшируются на сервере и переиспользуются на клиенте\n\nЭто мощный инструмент для оптимизации производительности Nuxt приложений!\n","dateCreated":"2026-04-02T22:26:11.323117","upvoteCount":0,"author":{"@type":"Person","name":"claude-haiku-4.5"}}}}
← Назад к вопросам

Как закэшировать данные в useAsyncData?

1.0 Junior🔥 131 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Кэширование данных в useAsyncData (Nuxt)

Я в основном работаю с React, но useAsyncData — это композабл из Nuxt 3 для загрузки асинхронных данных с встроенным кэшированием. Вот полный гайд.

Базовое использование useAsyncData

// pages/user/[id].vue
<script setup lang="ts">
const route = useRoute();
const userId = route.params.id as string;

const { data: user, pending, error } = await useAsyncData(
  `user-${userId}`, // ключ кэша (уникальный идентификатор)
  () => $fetch(`/api/users/${userId}`) // функция для загрузки
);
</script>

<template>
  <div>
    <div v-if="pending">Loading...</div>
    <div v-else-if="error">Error: {{ error.message }}</div>
    <div v-else>
      <h1>{{ user.name }}</h1>
      <p>{{ user.email }}</p>
    </div>
  </div>
</template>

Этот код автоматически кэширует результат с ключом user-{userId}.

Как работает кэш в useAsyncData

1. Ключ кэша обязателен

// ✓ ПРАВИЛЬНО: уникальный ключ кэша
const { data } = await useAsyncData('products-list', () => fetchProducts());

// ✗ НЕПРАВИЛЬНО: нет ключа кэша
const { data } = await useAsyncData(null, () => fetchProducts());

Ключ должен быть:

  • Уникальным для каждого запроса
  • Консистентным (всегда один и тот же для одних данных)
  • Описательным (понимаем, что это кэш)

2. Динамические ключи

// Для динамических данных — включай переменные в ключ
const route = useRoute();
const userId = route.params.id;
const filter = route.query.filter;

const { data: user } = await useAsyncData(
  `user-${userId}-${filter}`, // включаем переменные
  () => $fetch(`/api/users/${userId}?filter=${filter}`)
);

// Причина: если меняется userId, нужен новый ключ
// Иначе будут показаны старые кэшированные данные

3. Кэширование на сервере и клиенте

// Nuxt 3 использует payload extraction
const { data, refresh } = await useAsyncData(
  'products',
  async () => {
    return await $fetch('/api/products');
  },
  {
    server: true, // выполнить на сервере (SSR)
    // Результат попадёт в payload.json и будет переиспользован на клиенте
  }
);

// На сервере: запрос выполнится
// На клиенте: данные возьмут из payload.json, новый запрос не будет

Опции useAsyncData

1. watch — пересчитывать при изменении

const userId = ref('1');

const { data: user } = await useAsyncData(
  `user-${userId.value}`,
  () => $fetch(`/api/users/${userId.value}`),
  {
    watch: [userId] // перезагрузить при изменении userId
  }
);

// Когда userId меняется:
// 1. Nuxt видит изменение через watch
// 2. Видит, что ключ кэша изменился (user-1 -> user-2)
// 3. Запрашивает новые данные
// 4. Кэширует под новым ключом

2. pick — выбрать свойства из ответа

const { data } = await useAsyncData(
  'user',
  () => $fetch('/api/user'),
  {
    pick: ['id', 'name', 'email'] // кэширует только эти поля
    // остальное (address, phone) не попадёт в payload
  }
);

3. transform — трансформировать данные

const { data: formattedUser } = await useAsyncData(
  'user',
  () => $fetch('/api/user'),
  {
    transform: (data) => ({
      ...data,
      displayName: `${data.firstName} ${data.lastName}`,
      isAdmin: data.role === 'admin'
    })
  }
);
// Кэшируются трансформированные данные

4. dedupe — дедубликация запросов

// Если несколько компонентов одновременно запрашивают одни данные
const { data: users } = await useAsyncData(
  'users',
  () => $fetch('/api/users'),
  {
    dedupe: 'cancel' // отменить дубликаты запросов
    // вместо 3 запросов будет 1
  }
);

Управление кэшем вручную

1. Функция refresh() — пересчитать данные

const { data, refresh, pending } = await useAsyncData(
  'products',
  () => $fetch('/api/products')
);

const handleRefresh = async () => {
  // Пересчитать данные (игнорируя кэш)
  await refresh();
};

2. clear() — очистить кэш

const { clear } = await useAsyncData('products', () => fetchProducts());

// Где-то в приложении
const handleClearCache = () => {
  clear(); // кэш удалён, следующий вызов будет запрос
};

3. useAsyncData vs $fetch

// useAsyncData — с кэшем и SSR
const { data } = await useAsyncData('products', () => $fetch('/api/products'));

// $fetch — просто запрос, без кэша
const data = await $fetch('/api/products');

// Используй useAsyncData для:
// - Данных, которые используются в нескольких компонентах
// - SSR (рендеринг на сервере)
// - Кэширования результатов

// Используй $fetch для:
// - One-time запросов
// - Отправки данных (POST, PUT)
// - Когда кэш не нужен

Практические примеры

Пример 1: Список товаров с фильтром

<script setup lang="ts">
const route = useRoute();
const category = computed(() => route.query.category as string);
const sort = computed(() => route.query.sort as string);

const { data: products, refresh } = await useAsyncData(
  () => `products-${category.value}-${sort.value}`, // динамический ключ
  () => $fetch('/api/products', {
    query: { category: category.value, sort: sort.value }
  }),
  {
    watch: [category, sort] // пересчитать при изменении
  }
);
</script>

<template>
  <div>
    <FilterPanel @change="refresh" />
    <ProductList :products="products" />
  </div>
</template>

Пример 2: Глобальный кэш (composable)

// composables/useProducts.ts
export const useProducts = () => {
  return useAsyncData(
    'products-list', // один ключ для всех компонентов
    () => $fetch('/api/products'),
    {
      server: true // кэширует на сервере
    }
  );
};

// components/ProductList.vue
<script setup lang="ts">
const { data: products } = await useProducts();
// Если несколько компонентов используют этот composable,
// они получат данные из одного кэша
</script>

Пример 3: Инвалидация кэша после мутации

const { data: user, refresh } = await useAsyncData(
  'current-user',
  () => $fetch('/api/user')
);

const handleUpdateProfile = async (updates) => {
  await $fetch('/api/user', {
    method: 'PUT',
    body: updates
  });
  
  // Инвалидировать кэш и пересчитать
  await refresh();
};

Пример 4: Nested data с кэшем

// Сложная структура данных
const { data } = await useAsyncData(
  'dashboard',
  async () => {
    const [user, stats, settings] = await Promise.all([
      $fetch('/api/user'),
      $fetch('/api/stats'),
      $fetch('/api/settings')
    ]);
    
    return { user, stats, settings };
  },
  {
    pick: ['user.id', 'user.name', 'stats.totalVisits']
    // кэшируется только выбранные поля
  }
);

Сравнение с React (SWR / React Query)

В React аналогичный функционал:

// React Query (современный стандарт)
import { useQuery } from '@tanstack/react-query';

const { data, isLoading, refetch } = useQuery({
  queryKey: ['user', userId], // ключ кэша
  queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
  staleTime: 5 * 60 * 1000 // кэш свеж 5 минут
});

// SWR
import useSWR from 'swr';

const { data, error, mutate } = useSWR(
  userId ? `/api/users/${userId}` : null, // ключ кэша
  fetcher
);

Best Practices

1. Ключи должны быть уникальны и описательны

useAsyncData('user-profile-123', ...)
✓ useAsyncData('products-category-electronics', ...)
✗ useAsyncData('data', ...) // слишком общийuseAsyncData(`${Math.random()}`, ...) // не консистентный

2. Включай переменные в ключ кэша

const userId = route.params.id;

✓ useAsyncData(`user-${userId}`, () => fetchUser(userId))
✗ useAsyncData('user', () => fetchUser(userId)) // ключ не меняется

3. Используй watch для реактивности

const filter = ref('all');

✓ useAsyncData(
    () => `products-${filter.value}`,
    () => fetchProducts(filter.value),
    { watch: [filter] }
  )

✗ useAsyncData(
    'products',
    () => fetchProducts(filter.value)
    // filter меняется, но кэш не обновляется
  )

4. Инвалидируй кэш после мутаций

const { refresh } = await useAsyncData('user', fetchUser);

const updateUser = async (data) => {
  await postUpdate(data);
  await refresh(); // обновить кэш
};

5. Используй pick для оптимизации payload

// Кэшируется полный ответ API (может быть большим)useAsyncData('user', () => $fetch('/api/user'))

// Кэшируются только нужные поляuseAsyncData(
    'user',
    () => $fetch('/api/user'),
    { pick: ['id', 'name', 'email'] }
  )

Итог

Кэширование в useAsyncData:

  1. Ключ кэша — обязательный, уникальный идентификатор
  2. Динамические ключи — включай переменные для разных данных
  3. watch — пересчитывать при изменении зависимостей
  4. refresh() — инвалидировать и пересчитать кэш
  5. pick — оптимизировать размер payload на сервере
  6. SSR — данные кэшируются на сервере и переиспользуются на клиенте

Это мощный инструмент для оптимизации производительности Nuxt приложений!

Как закэшировать данные в useAsyncData? | PrepBro