Skip to main content

Чому try...catch не ловить помилки всередині JSX?

Коротка відповідь:

try...catch не ловить помилки всередині JSX, тому що JSX - це не виконуваний код у момент написання, а опис UI, який React обробляє асинхронно і поза вашим стеком викликів.


Що відбувається під капотом

Коли ти пишеш щось на кшталт:

javascript
function App() { try { return ( <div> <UserCard user={user} /> </div> ); } catch (e) { console.error('Помилка:', e); return <ErrorMessage />; } }

здається, ніби try...catch має зловити будь-яку помилку всередині UserCard. Але React працює не напряму: JSX перетворюється на об'єкт опису дерева елементів, а рендеринг і виконання компонентів відбуваються пізніше - у самому React, уже в іншому стеку викликів.


Візуально

  1. Ти викликаєш App().
  2. React викликає твій компонент → отримує об'єкт дерева:
javascript
{ type: "div", props: { children: <UserCard user={user} /> } }
  1. Потім React сам викликає UserCard() пізніше (всередині свого алгоритму Fiber). Якщо в UserCard() станеться помилка → вона виникне всередині React, а не в тому місці, де стояв твій try...catch.

Тому:

javascript
try { <UserCard user={user} /> // <-- це не виклик функції, а просто опис } catch (e) { // сюди не потрапить }

нічого не перехоплює, тому що помилка виникне пізніше, під час роботи React, а не в момент "читання" JSX.


Аналогія

Уяви, що JSX - це не "виконання", а "креслення інтерфейсу". Ти описав, що потрібно намалювати, але малює React "у фоні". Якщо в процесі "малювання" станеться помилка, твій try...catch про це не дізнається, бо код уже давно вийшов із твоєї функції.


Приклад помилки

javascript
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:

javascript
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; } }

Використання:

javascript
<ErrorBoundary> <UserCard /> </ErrorBoundary>

Тепер помилка всередині UserCard перехоплюється, і UI не падає.


2. try...catch у подіях або ефектах

try...catch працює, якщо помилка виникає у твоєму синхронному стеку, наприклад, в onClick або useEffect.

javascript
<button onClick={() => { try { throw new Error("Помилка в обробнику"); } catch (e) { console.error("Спіймана:", e); } }} > Натисни </button>

Тут помилка буде спіймана, тому що код виконується напряму в момент кліку.


3. Асинхронні помилки (try...catch + async/await)

javascript
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.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.