Пошук уроків, статей та іншого контенту
Реалізуєте спеціальні error.tsx і not-found.tsx для обробки помилок та сторінок із відсутніми даними.
error.tsx і not-found.tsxУ Next.js App Router спеціальні файли дозволяють створювати обробники для двох різних ситуацій:
error.tsx — непередбачена помилка під час рендерингу маршруту;
not-found.tsx — сторінка для ситуації, коли потрібні дані або маршрут не знайдено.
Ці файли діють у межах сегмента маршруту, у якому розташовані. Наприклад:
app/
├── error.tsx
├── not-found.tsx
└── products/
├── error.tsx
├── not-found.tsx
└── [id]/
└── page.tsxЧим ближче спеціальний файл до маршруту, тим специфічнішою буде його дія.
error.tsxФайл error.tsx створює Error Boundary для поточного сегмента маршруту та його дочірніх сегментів.
Оскільки цей компонент використовує React-механізм обробки помилок, він повинен бути клієнтським:
'use client';Мінімальна структура error.tsx:
'use client';
type ErrorPageProps = {
error: Error & {
digest?: string;
};
reset: () => void;
};
export default function ErrorPage({
error,
reset,
}: ErrorPageProps) {
return (
<main>
<h2>Щось пішло не так</h2>
<button onClick={() => reset()}>
Спробувати ще раз
</button>
</main>
);
}errorerror містить інформацію про помилку:
message — повідомлення помилки;
stack — стек викликів у середовищі розробки;
digest — ідентифікатор помилки, який Next.js може використовувати для зіставлення помилки із записом у логах.
Не слід показувати користувачеві повний stack або внутрішні деталі помилки в production.
resetreset — функція без аргументів, яка повторно намагається відрендерити сегмент маршруту.
Її можна використати, якщо причина помилки була тимчасовою, наприклад:
короткочасна недоступність API;
помилка мережі;
тимчасова помилка під час отримання даних.
error.tsxСтворимо компонент обробки помилок для розділу товарів:
// app/products/error.tsx
'use client';
import { useEffect } from 'react';
type ProductsErrorProps = {
error: Error & {
digest?: string;
};
reset: () => void;
};
export default function ProductsError({
error,
reset,
}: ProductsErrorProps) {
useEffect(() => {
// У production тут можна передати помилку до системи моніторингу
console.error(error);
}, [error]);
return (
<main>
<h1>Не вдалося завантажити товари</h1>
<p>Спробуйте повторити запит.</p>
<button type="button" onClick={reset}>
Повторити
</button>
</main>
);
}Цей компонент оброблятиме помилки зі сторінок усередині app/products, але не помилки батьківського layout.
Розглянемо сторінку товару, яка навмисно створює помилку для ідентифікатора error.
// app/products/[id]/page.tsx
type ProductPageProps = {
params: Promise<{
id: string;
}>;
};
const products = {
'1': {
name: 'Механічна клавіатура',
price: 3200,
},
'2': {
name: 'Бездротова миша',
price: 1800,
},
};
export default async function ProductPage({
params,
}: ProductPageProps) {
const { id } = await params;
if (id === 'error') {
throw new Error('Помилка під час завантаження товару');
}
const product = products[id as keyof typeof products];
if (!product) {
return <p>Товар не знайдено</p>;
}
return (
<main>
<h1>{product.name}</h1>
<p>Ціна: {product.price} грн</p>
</main>
);
}Для адреси /products/error буде створено помилку, і Next.js покаже найближчий error.tsx.
У режимі розробки Next.js також може показувати власну панель помилки поверх сторінки. Остаточний UI із error.tsx найкраще перевіряти у production-збірці.
notFound()Якщо сторінка не може бути показана, тому що потрібний ресурс не існує, не варто створювати звичайну помилку.
Для цього використовується функція notFound із next/navigation:
import { notFound } from 'next/navigation';Виклик notFound() припиняє поточний рендеринг і показує найближчий not-found.tsx.
Це підходить для ситуацій, коли:
товар не існує;
статтю видалено;
користувача з таким ідентифікатором не знайдено;
API повернуло дані, які означають відсутній ресурс.
not-found.tsxФайл not-found.tsx за замовчуванням є серверним компонентом:
// app/not-found.tsx
export default function NotFound() {
return (
<main>
<h1>Сторінку не знайдено</h1>
<p>Перевірте адресу або поверніться на головну сторінку.</p>
</main>
);
}Кореневий app/not-found.tsx може використовуватися для:
викликів notFound() у маршрутах;
URL, для яких у застосунку немає відповідного маршруту.
notFound() для відсутнього товаруЗмінимо сторінку товару:
// app/products/[id]/page.tsx
import { notFound } from 'next/navigation';
type ProductPageProps = {
params: Promise<{
id: string;
}>;
};
const products = {
'1': {
name: 'Механічна клавіатура',
price: 3200,
},
'2': {
name: 'Бездротова миша',
price: 1800,
},
};
export default async function ProductPage({
params,
}: ProductPageProps) {
const { id } = await params;
if (id === 'error') {
throw new Error('Помилка під час завантаження товару');
}
const product = products[id as keyof typeof products];
if (!product) {
notFound();
}
return (
<main>
<h1>{product.name}</h1>
<p>Ціна: {product.price} грн</p>
</main>
);
}Тепер:
/products/1 покаже товар;
/products/2 покаже товар;
/products/999 покаже not-found.tsx;
/products/error покаже error.tsx.
Після виклику notFound() виконання цього рендерингу припиняється, тому Next.js розуміє, що значення product існує після цієї перевірки.
not-found.tsxІноді для різних частин застосунку потрібні різні повідомлення. Тоді not-found.tsx можна розмістити ближче до потрібного маршруту:
// app/products/not-found.tsx
export default function ProductsNotFound() {
return (
<main>
<h1>Товар не знайдено</h1>
<p>
Перевірте ідентифікатор товару або перегляньте весь каталог.
</p>
</main>
);
}Тепер виклик notFound() у маршрутах усередині app/products використовуватиме цю локальну сторінку замість кореневої.
Розташування спеціального файлу визначає його область дії:
app/
├── error.tsx # Загальний обробник помилок
├── not-found.tsx # Загальна сторінка 404
└── products/
├── error.tsx # Помилки в розділі products
├── not-found.tsx # Відсутні дані в розділі products
└── [id]/
└── page.tsxЯкщо в app/products/[id]/ немає власних error.tsx або not-found.tsx, Next.js шукатиме їх у батьківських сегментах.
Це дозволяє:
використовувати єдиний загальний дизайн для всього застосунку;
створювати спеціальні повідомлення для окремих розділів;
не дублювати обробку однакових ситуацій у кожній сторінці.
error.tsx і not-found.tsx: коли що використовуватиВикористовуйте error.tsx, якщо сталася помилка:
throw new Error('Не вдалося отримати відповідь від API');Використовуйте notFound(), якщо ресурс відсутній:
if (!product) {
notFound();
}Не варто використовувати throw new Error() для звичайної ситуації «дані не знайдено». Відсутній ресурс не обов’язково є помилкою сервера, тому для нього призначений notFound().
'use client' у error.tsxerror.tsx використовує клієнтські можливості React. Без директиви компонент не працюватиме як Error Boundary:
'use client';Директива повинна бути на початку файлу, до імпортів.
notFound без імпортуФункцію потрібно імпортувати з next/navigation:
import { notFound } from 'next/navigation';Не виводьте користувачеві error.stack, SQL-запити, службові URL або інші внутрішні дані. Для користувача достатньо зрозумілого повідомлення, а технічну інформацію можна записати в лог або систему моніторингу.
error.tsxЯкщо товар не знайдено, це зазвичай не серверна помилка:
if (!product) {
notFound();
}error.tsx призначений для неочікуваних помилок, а not-found.tsx — для відсутніх маршрутів або даних.
error.tsx обробить подію кнопкиerror.tsx обробляє помилки під час рендерингу та роботи сегмента маршруту. Помилки, які виникають усередині обробника події кнопки, не перехоплюються цим Error Boundary автоматично. Такі помилки потрібно обробляти безпосередньо в коді обробника.
error.tsx показує запасний інтерфейс для неочікуваних помилок.
error.tsx повинен містити 'use client'.
Проп error містить інформацію про помилку.
Функція reset() повторює спробу відрендерити сегмент.
notFound() використовується, коли ресурс або маршрут не існує.
not-found.tsx показує сторінку для відсутніх даних.
Спеціальні файли діють у межах свого маршруту та найближчих дочірніх сегментів.
Для відсутніх даних використовуйте notFound(), а для неочікуваних збоїв — throw і error.tsx.