Получение данных в Next.js: useEffect, SWR и isomorphic-unfetch
Зачем управляивать способами получения данных
Получение данных — ключевая часть любого приложения на Next.js. От выбранного подхода зависят быстродействие, SEO, пользовательский опыт и сложность поддержки. Эти подходы решают разные задачи:
- Быстрая отдача HTML для SEO и первого рендера — server-side или статическая генерация.
- Динамические, персонализированные страницы для авторизованных пользователей — клиентский fetch и useEffect.
- Частые обновления данных и удобная логика кеширования — SWR.
- Поддержка серверного окружения и старых браузеров — isomorphic-unfetch.
Важно: в Next.js есть серверные методы (getStaticProps, getServerSideProps, Incremental Static Regeneration), которые тоже часто подходят для получения данных. В этой статье мы сосредоточимся на трёх подходах, описанных выше, и добавим рекомендации по выбору.
useEffect: когда и как использовать
useEffect — это React-хук для побочных эффектов. Его применяют, когда данные должны загружаться на клиенте после первого рендера. Примеры: панель пользователя, динамические виджеты, данные, зависящие от состояния браузера.
Короткое определение: useEffect запускает функцию после рендера компонента; dependency array управляет, когда эффект повторяется.
Пример корректного кода с проверками и обработкой ошибок:
import { useEffect, useState } from 'react';
export default function Home() {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let isMounted = true; // защита от обновления состояния после unmount
fetch('https://api.example.com/data')
.then((response) => {
if (!response.ok) throw new Error('Network response was not ok');
return response.json();
})
.then((json) => {
if (isMounted) setData(json);
})
.catch((err) => {
if (isMounted) setError(err);
})
.finally(() => {
if (isMounted) setLoading(false);
});
return () => {
isMounted = false;
};
}, []);
if (loading) return Загрузка...;
if (error) return Ошибка: {error.message};
return (
{data?.name}
{JSON.stringify(data, null, 2)}
);
}Когда использовать useEffect:
- Данные полностью персональны и не нужны для SEO.
- Данные зависят от окна браузера, localStorage или cookies на клиенте.
- Вы хотите выполнять запросы после первого рендера или при изменении зависимостей.
Ограничения useEffect:
- Контент появляется уже после первого рендера, поэтому плох для SEO.
- Нужно управлять состоянием загрузки и ошибками вручную.
SWR: автоматическая ревалидция и удобное кеширование
SWR — библиотека от Vercel, реализующая стратегию stale-while-revalidate. Она удобна, когда данные часто обновляются, а приложение должно оставаться отзывчивым и консистентным.
Короткое определение: SWR кеширует данные и при повторном доступе отдаёт старые данные, одновременно подгружая свежие.
Простой пример использования SWR:
import useSWR from 'swr';
const fetcher = (url) => fetch(url).then((res) => {
if (!res.ok) throw new Error('Network response was not ok');
return res.json();
});
export default function Profile() {
const { data, error, isLoading } = useSWR('https://api.example.com/data', fetcher);
if (isLoading) return Загрузка...;
if (error) return Ошибка: {error.message};
return {data.name};
}Параметры revalidation, которые часто применяют:
const { data } = useSWR('/api/data', fetcher, {
revalidateOnFocus: false, // не рефетчить при возврате фокуса
revalidateOnReconnect: true, // рефетчить при восстановлении сети
refreshInterval: 0, // отключить периодический рефетч
});Когда выбирать SWR:
- Данные часто меняются и их нужно держать свежими.
- Нужен простой кеш с политиками ревалидации.
- Хотите использовать оптимистическое обновление и мутировать кеш локально.
Ограничения SWR:
- Это клиентская библиотека; для первичного рендера с SEO предпочтительнее server-side методы.
- Нужно понять, какие опции ревалидации вам подходят, иначе можно получить неожиданные запросы.
Важно: опции называются revalidateOnFocus и revalidateOnReconnect. Для полной отключки автоматической ревалидции установите обе опции в false.
isomorphic-unfetch: когда нужен полифилл
isomorphic-unfetch — минималистичный пакет, обеспечивающий fetch как на клиенте, так и на сервере (Node). Это полезно, если вы хотите унифицировать вызовы fetch в разных окружениях и поддержать старые браузеры.
Короткое определение: isomorphic-unfetch предоставляет fetch API там, где его нет, и не навязывает дополнительных зависимостей.
Установка:
npm install isomorphic-unfetchПример использования и исправления распространённых ошибок:
import fetch from 'isomorphic-unfetch';
import { useState, useEffect } from 'react';
export default function Home() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let mounted = true;
fetch('https://api.example.com/data')
.then((res) => {
if (!res.ok) throw new Error('Network response was not ok');
return res.json();
})
.then((json) => {
if (mounted) setData(json);
})
.catch((err) => {
if (mounted) setError(err);
})
.finally(() => {
if (mounted) setLoading(false);
});
return () => {
mounted = false;
};
}, []);
if (loading) return Loading...;
if (error) return Error: {error.message};
return (
{data.name}
);
}Когда использовать isomorphic-unfetch:
- Нужно простое решение для fetch на сервере и клиенте без лишних зависимостей.
- Вы хотите совместимость с окружениями, где глобального fetch нет.
Ограничения:
- Не предоставляет кеширования и стратегий ревалидации, как SWR.
- Менее функционален по сравнению с более крупными библиотеками (axios, ky, undici).
Альтернативы и частые композиции
- getStaticProps / getServerSideProps: для рендера на сервере и SEO. Часто используются вместе с SWR: сервер отдаёт начальные данные, а SWR берёт и ревалидирует их на клиенте.
- React Query: альтернатива SWR с похожим набором возможностей и более богатой экосистемой мутаций и пагинации.
- axios/ky: если нужна расширенная обработка запросов и interceptors.
Пример шаблона: server-side initial data + SWR
// pages/index.js
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/data');
const initialData = await res.json();
return { props: { initialData } };
}
// компонент
import useSWR from 'swr';
function Page({ initialData }) {
const { data } = useSWR('/api/data', fetcher, { fallbackData: initialData });
return {data.name};
}Сравнительная матрица (быстрая)
| Подход | Где работает | SEO | Кеширование | Простота | Когда подходит |
|---|---|---|---|---|---|
| useEffect | Клиент | Плохо | Нет | Простo | Персонализация, client-only данные |
| SWR | Клиент | Умеренно | Да, встроено | Средне | Частые обновления, оптимистичные обновления |
| isomorphic-unfetch | Клиент + сервер | Зависит от использования | Нет | Очень просто | Унификация fetch между средами |
| getServerSideProps | Сервер | Отлично | По запросу | Сложнее | SEO, динамический SSR |
| getStaticProps | Сервер (SSG) | Отлично | Статично, ISR | Сложнее | Статический контент, ISR |
Ментальные модели и эвристики для выбора
- Если нужно SEO и быстрый первый рендер — server-side (getServerSideProps) или SSG (getStaticProps).
- Если данные персональные и могут ждать — fetch в useEffect.
- Если данные часто меняются, но не критичны для SEO — SWR.
- Если хотите единый fetch в клиенте и на сервере — isomorphic-unfetch.
Decision flowchart
flowchart TD
A[Нужен ли быстрый SEO-рендер?] -->|Да| B[getStaticProps или getServerSideProps]
A -->|Нет| C[Данные персональные?]
C -->|Да| D[useEffect]
C -->|Нет| E[Данные часто меняются?]
E -->|Да| F[SWR]
E -->|Нет| G[isomorphic-unfetch или fetch]Ролевые чек-листы
Разработчик:
- Проверить требования к SEO.
- Выбрать подходящий метод для рендера.
- Обработать ошибки и состояния загрузки.
- Защитить обновления состояния после unmount.
Технический лидер:
- Оценить TCO поддержки выбранного решения.
- Проверить безопасность и retry-политики.
- Решить стратегию кеширования и инвалидации.
QA инженер:
- Покрыть сценарии offline/online.
- Протестировать revalidation и edge-cases.
- Проверить поведение при долгих запросах и таймаутах.
Критерии приёмки
- Страница корректно отображает загрузку, ошибку и успешный результат.
- Не происходит утечек состояния при unmount.
- Для SEO-страниц контент доступен на первичном HTML-рендере.
- Для SWR: политики revalidate настроены согласно требованиям продукта.
Факто-бокс
- SWR реализует стратегию stale-while-revalidate: отдаёт старые данные и параллельно получает свежие.
- useEffect выполняется на клиенте после рендера компонента.
- isomorphic-unfetch даёт fetch в окружениях без глобального fetch.
Примеры ошибок и их решения
- Ошибка: response.json без вызова функции. Решение: использовать response.json()
- Ошибка: обновление state после размонтирования. Решение: флаг mounted или AbortController.
- Проблема: частые невидимые запросы SWR. Решение: настроить revalidateOnFocus, revalidateOnReconnect, refreshInterval.
Короткий чек при выборе
- Нужен ли контент в HTML для SEO? Да → server-side.
- Данные пользовательские и не критичны для SEO? Да → useEffect.
- Данные часто меняются и требуются свежие значения? Да → SWR.
- Нужен единый fetch для серверной и клиентской части? Да → isomorphic-unfetch.
Часто задаваемые вопросы
Нужно ли использовать SWR вместе с getStaticProps?
Да. Паттерн fallbackData или initialData позволяет отдавать предрендеренные данные и одновременно revalidate их на клиенте.
Как отключить автоматическую ревалидацию в SWR?
Установите revalidateOnFocus: false и revalidateOnReconnect: false в опциях useSWR.
Чем isomorphic-unfetch отличается от native fetch?
isomorphic-unfetch обеспечивает наличие fetch в окружениях, где он отсутствует, например в старых версиях Node или браузеров.
Короткое резюме
Выбор способа получения данных в Next.js зависит от требований: SEO, динамичности, частоты обновлений и окружения. useEffect хорош для клиентских случаев, SWR — для кеша и ревалидации, isomorphic-unfetch — для унифицированного fetch.
Важно адаптировать стратегию под конкретную задачу: комбинируйте server-side initial data с клиентским SWR для лучшего UX и SEO.
Похожие материалы
Использование KeePass: пароли и группы
Как исправить «Служба Google Play остановлена»
Автоматизация Chrome: iMacros и Wildfire
Как удалить бизнес из Google My Business
Изменить папку загрузок в Google Chrome