Чому try...catch не ловить помилки всередині JSX?
Коротка відповідь:
try...catchне ловить помилки всередині JSX, тому що JSX - це не виконуваний код у момент написання, а опис UI, який React обробляє асинхронно і поза вашим стеком викликів.
Що відбувається під капотом
Коли ти пишеш щось на кшталт:
function App() {
try {
return (
<div>
<UserCard user={user} />
</div>
);
} catch (e) {
console.error('Помилка:', e);
return <ErrorMessage />;
}
}здається, ніби try...catch має зловити будь-яку помилку всередині UserCard.
Але React працює не напряму: JSX перетворюється на об'єкт опису дерева елементів,
а рендеринг і виконання компонентів відбуваються пізніше - у самому React,
уже в іншому стеку викликів.
Візуально
- Ти викликаєш
App(). - React викликає твій компонент → отримує об'єкт дерева:
{ type: "div", props: { children: <UserCard user={user} /> } }- Потім React сам викликає
UserCard()пізніше (всередині свого алгоритму Fiber). Якщо вUserCard()станеться помилка → вона виникне всередині React, а не в тому місці, де стояв твійtry...catch.
Тому:
try {
<UserCard user={user} /> // <-- це не виклик функції, а просто опис
} catch (e) {
// сюди не потрапить
}нічого не перехоплює, тому що помилка виникне пізніше, під час роботи React, а не в момент "читання" JSX.
Аналогія
Уяви, що JSX - це не "виконання", а "креслення інтерфейсу".
Ти описав, що потрібно намалювати, але малює React "у фоні".
Якщо в процесі "малювання" станеться помилка,
твій try...catch про це не дізнається, бо код уже давно вийшов із твоєї функції.
Приклад помилки
function UserCard({ user }) {
return <div>{user.name}</div>; // user === undefined → помилка
}
function App() {
try {
return <UserCard />; // try не зловить
} catch (e) {
console.error("Помилка в рендері!", e);
return <h1>Помилка!</h1>;
}
}React сам "зловить" помилку і прокине її вгору - якщо поруч є Error Boundary, він покаже fallback. Якщо немає - застосунок "впаде" (white screen).
Що справді ловить такі помилки
1. Error Boundary
Класовий компонент з componentDidCatch або getDerivedStateFromError:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error('Помилка в компоненті:', error);
}
render() {
return this.state.hasError ? <h1>Щось пішло не так</h1> : this.props.children;
}
}Використання:
<ErrorBoundary>
<UserCard />
</ErrorBoundary>Тепер помилка всередині UserCard перехоплюється, і UI не падає.
2. try...catch у подіях або ефектах
try...catch працює, якщо помилка виникає у твоєму синхронному стеку,
наприклад, в onClick або useEffect.
<button
onClick={() => {
try {
throw new Error("Помилка в обробнику");
} catch (e) {
console.error("Спіймана:", e);
}
}}
>
Натисни
</button>Тут помилка буде спіймана, тому що код виконується напряму в момент кліку.
3. Асинхронні помилки (try...catch + async/await)
useEffect(() => {
async function loadData() {
try {
const res = await fetch('/api/data');
const json = await res.json();
setData(json);
} catch (e) {
console.error("Помилка під час завантаження:", e);
}
}
loadData();
}, []);Тут усе працює як зазвичай: помилка ловиться, тому що вона виникає всередині твого контексту виконання.
Чому не можна просто загорнути все в try...catch
Тому що React керує порядком викликів компонентів сам, і може рендерити компоненти:
- асинхронно (у concurrent режимі);
- двічі (у Strict Mode);
- з відкладеним виконанням.
try...catch просто не має доступу до цих стеків виконання.
Підсумок:
| Сценарій | Ловиться try...catch? | Чому |
|---|---|---|
Помилка в JSX (<UserCard />) | Ні | Рендерингом керує React |
Помилка в useEffect | Так | Код виконується в твоєму стеку |
Помилка в onClick | Так | Обробник - звичайна функція |
| Помилка в асинхронному коді (await) | Так (якщо загорнута) | try...catch працює з await |
| Помилка в компоненті без Error Boundary | Ні | React розмонтує дерево |
Висновок:
try...catchне ловить помилки всередині JSX, тому що рендеринг компонентів виконується поза вашим стеком викликів, усередині самого React.Для таких помилок потрібні Error Boundaries - це "React-версія try/catch" на рівні UI.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.