Префетчинг данных

Префетчинг данных — это подход, при котором необходимые для компонента данные загружаются заранее, еще до того, как пользователь откроет соответствующий маршрут. В контексте Vue Router это позволяет улучшить пользовательский опыт, снижая задержки при переходе между страницами.


Использование beforeEnter для предзагрузки данных

Каждый маршрут в Vue Router может иметь собственный навигационный guard. beforeEnter выполняется перед входом на маршрут и позволяет инициировать асинхронные операции.

import { createRouter, createWebHistory } from 'vue-router';
import UserProfile from './components/UserProfile.vue';
import { fetchUserData } from './api';

const routes = [
  {
    path: '/user/:id',
    component: UserProfile,
    beforeEnter: async (to, from, next) => {
      try {
        const data = await fetchUserData(to.params.id);
        to.meta.prefetchedData = data;
        next();
      } catch (error) {
        next('/error');
      }
    }
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;

В этом примере данные пользователя загружаются до отображения компонента. Сохранение данных в to.meta позволяет компоненту получить их сразу при монтировании, без дополнительных запросов.


Префетчинг с использованием setup и Composition API

В Composition API можно комбинировать Vue Router и асинхронную загрузку данных:

import { onBeforeRouteEnter } from 'vue-router';
import { ref } from 'vue';
import { fetchUserData } from '../api';

export default {
  setup() {
    const userData = ref(null);

    onBeforeRouteEnter(async (to, from, next) => {
      try {
        const data = await fetchUserData(to.params.id);
        next(vm => vm.userData = data);
      } catch {
        next('/error');
      }
    });

    return { userData };
  }
}

onBeforeRouteEnter предоставляет доступ к экземпляру компонента через коллбек next(vm => ...), что позволяет напрямую назначать предзагруженные данные в реактивные свойства.


Префетчинг на уровне родительского компонента

Для маршрутов с вложенными компонентами выгодно загружать данные на уровне родителя, чтобы дочерние компоненты сразу получали необходимую информацию.

<template>
  <div>
    <router-view :items="items" />
  </div>
</template>

<script>
import { ref, onMounted } from 'vue';
import { fetchItems } from '../api';

export default {
  setup() {
    const items = ref([]);

    onMounted(async () => {
      items.value = await fetchItems();
    });

    return { items };
  }
}
</script>

Дочерние маршруты получают данные через props, что позволяет избежать повторных запросов при переключении между дочерними страницами.


Lazy-loading маршрутов с предзагрузкой данных

Vue Router поддерживает динамический импорт компонентов, что уменьшает размер начальной сборки приложения. Префетчинг данных можно совмещать с ленивой загрузкой:

const UserProfile = () => import('./components/UserProfile.vue');

const routes = [
  {
    path: '/user/:id',
    component: UserProfile,
    beforeEnter: async (to, from, next) => {
      const data = await fetchUserData(to.params.id);
      to.meta.prefetchedData = data;
      next();
    }
  }
];

Совместное использование динамического импорта и beforeEnter позволяет минимизировать время ожидания при переходе, поскольку одновременно загружается компонент и необходимые данные.


Предзагрузка данных при ховере или предугадывании перехода

Для повышения скорости отклика интерфейса можно запускать асинхронные запросы заранее, еще до того, как пользователь перейдет по ссылке:

import { fetchUserData } from '../api';

function prefetchUserData(id) {
  fetchUserData(id).then(data => {
    // сохранить данные в глобальном состоянии или кэше
  });
}

// В шаблоне
<a @mouseenter="() => prefetchUserData(user.id)" :href="`/user/${user.id}`">Профиль</a>

Такой подход особенно полезен для навигации через меню или списки, где вероятность перехода высока. В сочетании с Vuex или Pinia можно хранить предзагруженные данные централизованно.


Обработка ошибок и fallback

При предзагрузке данных важно предусматривать обработку ошибок. Если запрос не удался, маршрут можно перенаправить на страницу ошибки или показать временный state:

beforeEnter: async (to, from, next) => {
  try {
    const data = await fetchUserData(to.params.id);
    to.meta.prefetchedData = data;
    next();
  } catch (error) {
    next({ path: '/error', query: { message: error.message } });
  }
}

Использование query-параметров позволяет передать информацию о причине сбоя и отобразить пользователю понятное сообщение.


Использование глобального навигационного guard для кэширования

Глобальный guard router.beforeEach позволяет централизованно управлять предзагрузкой данных для всех маршрутов:

router.beforeEach(async (to, from, next) => {
  if (to.meta.prefetch && !to.meta.prefetchedData) {
    try {
      const data = await fetchDataForRoute(to);
      to.meta.prefetchedData = data;
    } catch {
      return next('/error');
    }
  }
  next();
});

Это упрощает поддержку приложений с большим числом маршрутов, где нужно одинаково обрабатывать предварительную загрузку данных.


Выводы по префетчингу данных

Префетчинг в Vue Router повышает скорость отклика и улучшает пользовательский опыт, минимизируя задержки при переходе между маршрутами. Ключевые подходы включают:

  • Использование beforeEnter и глобальных guard для асинхронной загрузки данных.
  • Комбинацию Composition API и onBeforeRouteEnter.
  • Предзагрузку на уровне родительских компонентов для вложенных маршрутов.
  • Ленивая загрузка компонентов с одновременным предзагрузом данных.
  • Асинхронную предзагрузку при пользовательских событиях, таких как ховер.
  • Централизованное кэширование и обработку ошибок.

Эти техники позволяют создавать приложения на Vue, где переходы между страницами происходят мгновенно, а пользователи видят контент без лишних задержек.