Что такое getStaticPaths?
getStaticPaths — это асинхронная функция, предоставляемая Next.js, которая используется для генерации динамических маршрутов при статической генерации страниц (SSG). С её помощью мы можем указать, какие страницы должны быть сгенерированы на этапе сборки (build-time).
Если вы знакомы с понятием роутинга, представьте, что вам нужно создать страницы для пользователей с различными ID, например /user/1, /user/2, /user/3. getStaticPaths позволяет вам передать список этих ID (или других параметров) на этапе компиляции, чтобы Next.js мог заранее подготовить нужные маршруты.
Основной синтаксис
export async function getStaticPaths() {
return {
paths: [
{ params: { id: '1' } },
{ params: { id: '2' } },
],
fallback: false, // Подробнее о fallback чуть ниже
};
}
paths: массив объектов, каждый из которых описывает параметры (например,id) для рендера страницы.fallback: управляет поведением для маршрутов, которые не были включены вpaths. Это важно для работы с динамическими страницами.
Пример создания динамических страниц с getStaticPaths
Рассмотрим пример. У нас есть API, предоставляющее список продуктов, и мы хотим сгенерировать страницы для каждого из них. Допустим, API возвращает такой список:
[
{ "id": "1", "name": "Товар 1" },
{ "id": "2", "name": "Товар 2" },
{ "id": "3", "name": "Товар 3" }
]
Шаг 1: создадим динамический маршрут
Динамический маршрут в Next.js создаётся с использованием квадратных скобок в названии файла. Для нашего примера это будет файл pages/product/[id].tsx.
import { GetStaticPaths, GetStaticProps } from 'next';
interface ProductProps {
id: string;
name: string;
}
const ProductPage: React.FC<ProductProps> = ({ id, name }) => (
<div>
<h1>Продукт: {name}</h1>
<p>ID: {id}</p>
</div>
);
export default ProductPage;
Шаг 2: используем getStaticPaths
Теперь добавим логику для получения списка продуктов и генерации маршрутов.
export const getStaticPaths: GetStaticPaths = async () => {
const res = await fetch('https://example.com/api/products');
const products: { id: string }[] = await res.json();
const paths = products.map(product => ({
params: { id: product.id },
}));
return {
paths, // Генерируем маршруты для каждого продукта
fallback: false, // Об этом ниже
};
};
Шаг 3: используем getStaticProps для получения данных
getStaticProps позволяет получить данные для конкретной страницы на этапе сборки.
export const getStaticProps: GetStaticProps = async (context) => {
const { id } = context.params!;
const res = await fetch(`https://example.com/api/products/${id}`);
const product = await res.json();
return {
props: {
id: product.id,
name: product.name,
},
};
};
Теперь любой маршрут вида /product/1, /product/2 и т.д. будет работать!
Типизация возвращаемых данных с помощью TypeScript
Работа с динамическими маршрутами без типизации может привести к хаосу. Рассмотрим, как типизировать данные, возвращаемые в getStaticPaths и getStaticProps.
Типизация getStaticPaths
Сначала создадим интерфейс для описания параметров маршрута:
interface ProductParams {
id: string;
}
Теперь мы можем указать тип возвращаемых данных в getStaticPaths:
export const getStaticPaths: GetStaticPaths<ProductParams> = async () => {
const res = await fetch('https://example.com/api/products');
const products: ProductParams[] = await res.json();
const paths = products.map(product => ({
params: { id: product.id },
}));
return {
paths,
fallback: false,
};
};
Типизация getStaticProps
Для данных, которые мы получаем из API, тоже создадим интерфейс:
interface ProductData {
id: string;
name: string;
}
И применим его в getStaticProps:
export const getStaticProps: GetStaticProps<ProductData> = async (context) => {
const { id } = context.params as ProductParams;
const res = await fetch(`https://example.com/api/products/${id}`);
const product: ProductData = await res.json();
return {
props: product,
};
};
Теперь компоненты, использующие полученные данные, могут быть уверены, что форма данных соответствует ожиданиям.
fallback: False, True или "blocking"?
Параметр fallback оказывает большое влияние на поведение приложения. Рассмотрим три возможных значения:
fallback: false
Все маршруты, которые не указаны в paths, будут возвращать 404.
- Подходит для небольших проектов с фиксированным количеством страниц.
- Каждая страница должна быть предопределена на этапе сборки.
fallback: true
Страницы, не указанные в paths, будут генерироваться при первом запросе.
- Полезно для больших сайтов с большим количеством страниц.
- При первом запросе пользователь увидит "заглушку", пока генерируется страница.
export const getStaticPaths = () => ({
paths: [],
fallback: true,
});
fallback: 'blocking'
Похож на true, но пользователь будет ждать полной генерации страницы перед её отображением.
- Идеален для SEO, так как пользователь сразу получает готовую страницу.
export const getStaticPaths = () => ({
paths: [],
fallback: 'blocking',
});
Проблемы и особенности
Хотя getStaticPaths мощный инструмент, он может вызвать трудности:
- Ошибка "Too many pages to generate": если ваш API возвращает слишком много маршрутов, это может замедлить сборку. Решение: используйте
fallback: trueилиblocking. - Несогласованные данные: если данные изменились после генерации, пользователи увидят устаревшую информацию. Решение: добавьте функцию revalidate.
Советы по оптимизации
- Используйте типизацию данных с TypeScript, чтобы избежать ошибок.
- Старайтесь ограничивать список маршрутов для
getStaticPathsс помощью пагинации или фильтров. - Спланируйте стратегию работы с
fallbackв зависимости от ваших требований к производительности и SEO.
export const getStaticProps: GetStaticProps = async (context) => {
const { id } = context.params!;
// Добавьте обработку ошибок для недостающих данных
try {
const res = await fetch(`https://example.com/api/products/${id}`);
const product = await res.json();
if (!res.ok) throw new Error('Error fetching product');
return {
props: product,
revalidate: 10, // Перегенерируйте страницу каждые 10 секунд
};
} catch (error) {
return { notFound: true }; // Верните 404 для отсутствующего продукта
}
};
Теперь вы знаете, как использовать getStaticPaths для работы с динамическими маршрутами в Next.js. Это позволяет создавать масштабируемые приложения с урезанным временем загрузки. Ну а дальше — ещё больше чудес Next.js!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ