Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як використовувати стор Pinia поза компонентами і чим це небезпечно в SSR?

useStore() усередині setup знаходить активний екземпляр Pinia через inject. Поза компонентом (у guard роутера, інтерсепторі HTTP-клієнта, звичайному модулі) інжекту немає, і Pinia покладається на «активний» екземпляр, встановлений app.use(pinia).

Типова помилка - виклик на рівні модуля:

// api.js
const auth = useAuthStore();   // виконується при імпорті - ДО app.use(pinia)
// Error: getActivePinia() was called but there was no active Pinia

Правильно - викликати всередині функції, яка виконається пізніше:

router.beforeEach((to) => {
  const auth = useAuthStore();   // на момент навігації Pinia вже встановлена
  if (to.meta.requiresAuth && !auth.isLoggedIn) return '/login';
});

http.interceptors.request.use((config) => {
  const auth = useAuthStore();
  if (auth.token) config.headers.Authorization = `Bearer ${auth.token}`;
  return config;
});

Чому це критично в SSR. На сервері Node.js обслуговує багато запитів одним процесом. Якщо стор створюється на рівні модуля чи покладається на глобальний «активний» екземпляр, стан одного користувача може потрапити в запит іншого: кошик, профіль, токен.

Правила для SSR:

  • новий екземпляр Pinia (і роутера, і застосунку) на кожен запит - у фабричній функції createApp();
  • поза setup передавати pinia явно:
router.beforeEach((to) => {
  const auth = useAuthStore(pinia);   // саме той екземпляр, що належить цьому запиту
});
  • жодного стану на рівні модуля (let currentUser в імпортованому файлі) - він спільний для всіх запитів процесу.

Ще одна пастка - стори, що використовують один одного. Виклик useOtherStore() у тілі setup store - нормально, але циклічне читання стану двох сторів одне з одного під час створення призводить до помилок. Доступ до іншого стору краще робити в гетерах і діях, а не на верхньому рівні.

Тестування: у юніт-тестах сторів перед кожним тестом - setActivePinia(createPinia()), щоб тести не ділили стан.

Докладніше в документації: Pinia: використання поза компонентами

Схожі питання