Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Чому try...catch не ловить помилки всередині JSX?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)`try...catch` не ловить помилки всередині JSX, тому що **JSX - це не виконуваний код у момент написання**, а **опис UI**, який React **обробляє асинхронно і поза вашим стеком викликів**. **Ключове:** рендеринг компонентів виконується всередині самого React, тому для таких помилок потрібні **Error Boundaries** - "React-версія try/catch" на рівні UI.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Коротка відповідь: > `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} /> } } ``` 3. Потім 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.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.