Komplexní průvodce pro pochopení a implementaci JavaScript Error Boundaries v Reactu pro robustní zpracování chyb a plynulou degradaci UI.
JavaScript Error Boundary: Průvodce implementací zpracování chyb v Reactu
Ve světě vývoje v Reactu mohou neočekávané chyby vést k frustrujícím uživatelským zážitkům a nestabilitě aplikace. Dobře definovaná strategie pro zpracování chyb je klíčová pro tvorbu robustních a spolehlivých aplikací. Error Boundaries v Reactu poskytují mocný mechanismus pro elegantní zpracování chyb, které se vyskytnou ve stromu vašich komponent, zabraňují pádu celé aplikace a umožňují zobrazit záložní uživatelské rozhraní (UI).
Co je Error Boundary?
Error Boundary je React komponenta, která zachytává JavaScriptové chyby kdekoli ve svém stromu potomků, zaznamenává tyto chyby a zobrazuje záložní UI namísto stromu komponent, který selhal. Error Boundaries zachytávají chyby během renderování, v metodách životního cyklu a v konstruktorech celého stromu pod nimi.
Představte si Error Boundary jako blok try...catch
pro React komponenty. Stejně jako blok try...catch
umožňuje zpracovávat výjimky v synchronním JavaScriptovém kódu, Error Boundary vám umožňuje zpracovávat chyby, které nastanou během renderování vašich React komponent.
Důležitá poznámka: Error Boundaries nezachytávají chyby pro:
- Obslužné rutiny událostí (event handlery) (více se dozvíte v následujících sekcích)
- Asynchronní kód (např. callbacky
setTimeout
neborequestAnimationFrame
) - Renderování na straně serveru (Server-side rendering)
- Chyby vyvolané v samotné Error Boundary (spíše než v jejích potomcích)
Proč používat Error Boundaries?
Používání Error Boundaries nabízí několik významných výhod:
- Zlepšený uživatelský zážitek: Místo zobrazení prázdné bílé obrazovky nebo záhadné chybové hlášky můžete zobrazit uživatelsky přívětivé záložní UI, které informuje uživatele, že se něco pokazilo, a případně nabídne způsob obnovy (např. znovunačtení stránky nebo přechod do jiné sekce).
- Stabilita aplikace: Error Boundaries zabraňují, aby chyby v jedné části vaší aplikace způsobily pád celé aplikace. To je zvláště důležité pro komplexní aplikace s mnoha propojenými komponentami.
- Centralizované zpracování chyb: Error Boundaries poskytují centralizované místo pro logování chyb a sledování hlavní příčiny problémů. To zjednodušuje ladění a údržbu.
- Plynulá degradace (Graceful Degradation): Můžete strategicky umístit Error Boundaries kolem různých částí vaší aplikace, abyste zajistili, že i když některé komponenty selžou, zbytek aplikace zůstane funkční. To umožňuje plynulou degradaci v případě chyb.
Implementace Error Boundaries v Reactu
Pro vytvoření Error Boundary musíte definovat třídní komponentu, která implementuje jednu (nebo obě) z následujících metod životního cyklu:
static getDerivedStateFromError(error)
: Tato metoda životního cyklu je volána poté, co potomek vyvolá chybu. Přijímá vyvolanou chybu jako argument a měla by vrátit hodnotu pro aktualizaci stavu komponenty, aby indikovala, že došlo k chybě (např. nastavení příznakuhasError
natrue
).componentDidCatch(error, info)
: Tato metoda životního cyklu je volána poté, co potomek vyvolá chybu. Přijímá vyvolanou chybu jako argument, spolu s objekteminfo
obsahujícím informace o tom, která komponenta chybu vyvolala. Tuto metodu můžete použít k logování chyby do služby jako Sentry nebo Bugsnag.
Zde je základní příklad komponenty Error Boundary:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
error: null,
errorInfo: null
};
}
static getDerivedStateFromError(error) {
// Aktualizuje stav, aby další render zobrazil záložní UI.
return {
hasError: true,
error: error
};
}
componentDidCatch(error, info) {
// Příklad "componentStack":
// in ComponentThatThrows (created by App)
// in MyErrorBoundary (created by App)
// in div (created by App)
// in App
console.error("Caught an error:", error, info);
this.setState({
errorInfo: info.componentStack
});
// Chybu můžete také zalogovat do služby pro hlášení chyb
//logErrorToMyService(error, info.componentStack);
}
render() {
if (this.state.hasError) {
// Můžete renderovat jakékoliv vlastní záložní UI
return (
<div>
<h2>Něco se pokazilo.</h2>
<p>Chyba: {this.state.error ? this.state.error.message : "Vyskytla se neznámá chyba."}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.errorInfo && this.state.errorInfo}
</details>
</div>
);
}
return this.props.children;
}
}
Pro použití Error Boundary jednoduše obalte strom komponent, který chcete chránit:
<ErrorBoundary>
<MyComponentThatMightThrow/>
</ErrorBoundary>
Praktické příklady použití Error Boundary
Pojďme se podívat na několik praktických scénářů, kde mohou být Error Boundaries obzvláště užitečné:
1. Zpracování chyb API
Při načítání dat z API mohou nastat chyby kvůli problémům se sítí, problémům se serverem nebo neplatným datům. Komponentu, která načítá a zobrazuje data, můžete obalit do Error Boundary, abyste tyto chyby elegantně zpracovali.
function UserProfile() {
const [user, setUser] = React.useState(null);
const [isLoading, setIsLoading] = React.useState(true);
React.useEffect(() => {
async function fetchData() {
try {
const response = await fetch('/api/user');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setUser(data);
} catch (error) {
// Chyba bude zachycena komponentou ErrorBoundary
throw error;
} finally {
setIsLoading(false);
}
}
fetchData();
}, []);
if (isLoading) {
return <p>Načítání profilu uživatele...</p>;
}
if (!user) {
return <p>Nejsou dostupná žádná uživatelská data.</p>;
}
return (
<div>
<h2>{user.name}</h2>
<p>E-mail: {user.email}</p>
</div>
);
}
function App() {
return (
<ErrorBoundary>
<UserProfile />
</ErrorBoundary>
);
}
V tomto příkladu, pokud volání API selže nebo vrátí chybu, Error Boundary chybu zachytí a zobrazí záložní UI (definované v metodě render
komponenty Error Boundary). Tím se zabrání pádu celé aplikace a uživateli se poskytne informativnější zpráva. Záložní UI byste mohli rozšířit o možnost opakování požadavku.
2. Zpracování chyb knihoven třetích stran
Při používání knihoven třetích stran je možné, že mohou vyvolat neočekávané chyby. Obalení komponent, které tyto knihovny používají, pomocí Error Boundaries vám pomůže tyto chyby elegantně zpracovat.
Představte si hypotetickou knihovnu pro tvorbu grafů, která občas vyvolá chyby kvůli nekonzistenci dat nebo jiným problémům. Komponentu s grafem byste mohli obalit takto:
function MyChartComponent() {
try {
// Vykreslení grafu pomocí knihovny třetí strany
return <Chart data={data} />;
} catch (error) {
// Tento blok catch nebude účinný pro chyby životního cyklu React komponenty
// Je primárně určen pro synchronní chyby v rámci této konkrétní funkce.
console.error("Error rendering chart:", error);
// Zvažte vyvolání chyby, aby byla zachycena komponentou ErrorBoundary
throw error; // Opětovné vyvolání chyby
}
}
function App() {
return (
<ErrorBoundary>
<MyChartComponent />
</ErrorBoundary>
);
}
Pokud komponenta Chart
vyvolá chybu, Error Boundary ji zachytí a zobrazí záložní UI. Všimněte si, že try/catch uvnitř MyChartComponent zachytí pouze chyby v synchronní funkci, nikoli v životním cyklu komponenty. Proto je zde ErrorBoundary klíčová.
3. Zpracování chyb při renderování
Během procesu renderování se mohou vyskytnout chyby kvůli neplatným datům, nesprávným typům props nebo jiným problémům. Error Boundaries mohou tyto chyby zachytit a zabránit pádu aplikace.
function DisplayName({ name }) {
if (typeof name !== 'string') {
throw new Error('Jméno musí být řetězec');
}
return <h2>Dobrý den, {name}!</h2>;
}
function App() {
return (
<ErrorBoundary>
<DisplayName name={123} /> <!-- Nesprávný typ prop -->
</ErrorBoundary>
);
}
V tomto příkladu komponenta DisplayName
očekává, že prop name
bude řetězec. Pokud je místo toho předáno číslo, bude vyvolána chyba a Error Boundary ji zachytí a zobrazí záložní UI.
Error Boundaries a obslužné rutiny událostí
Jak již bylo zmíněno dříve, Error Boundaries nezachytávají chyby, které se vyskytnou v obslužných rutinách událostí (event handlerech). Je to proto, že obslužné rutiny událostí jsou obvykle asynchronní a Error Boundaries zachytávají pouze chyby, které se vyskytnou během renderování, v metodách životního cyklu a v konstruktorech.
Pro zpracování chyb v obslužných rutinách událostí musíte použít tradiční blok try...catch
uvnitř funkce obslužné rutiny.
function MyComponent() {
const handleClick = () => {
try {
// Nějaký kód, který může vyvolat chybu
throw new Error('V obslužné rutině události došlo k chybě');
} catch (error) {
console.error('Caught an error in the event handler:', error);
// Zpracujte chybu (např. zobrazte chybovou zprávu uživateli)
}
};
return <button onClick={handleClick}>Klikni na mě</button>;
}
Globální zpracování chyb
Ačkoli jsou Error Boundaries vynikající pro zpracování chyb ve stromu React komponent, nepokrývají všechny možné scénáře chyb. Například nezachytávají chyby, které se vyskytnou mimo React komponenty, jako jsou chyby v globálních posluchačích událostí nebo chyby v kódu, který se spustí před inicializací Reactu.
Pro zpracování těchto typů chyb můžete použít obslužnou rutinu události window.onerror
.
window.onerror = function(message, source, lineno, colno, error) {
console.error('Global error handler:', message, source, lineno, colno, error);
// Zalogujte chybu do služby jako Sentry nebo Bugsnag
// Zobrazte uživateli globální chybovou zprávu (volitelné)
return true; // Zabraňte výchozímu chování při zpracování chyb
};
Obslužná rutina události window.onerror
je volána, kdykoli dojde k nezachycené JavaScriptové chybě. Můžete ji použít k logování chyby, zobrazení globální chybové zprávy uživateli nebo k provedení dalších akcí pro zpracování chyby.
Důležité: Vrácení true
z obslužné rutiny události window.onerror
zabrání prohlížeči v zobrazení výchozí chybové zprávy. Mějte však na paměti uživatelský zážitek; pokud potlačíte výchozí zprávu, zajistěte, že poskytnete jasnou a informativní alternativu.
Osvědčené postupy pro používání Error Boundaries
Zde jsou některé osvědčené postupy, které je třeba mít na paměti při používání Error Boundaries:
- Umísťujte Error Boundaries strategicky: Obalte různé části vaší aplikace pomocí Error Boundaries, abyste izolovali chyby a zabránili jejich šíření. Zvažte obalení celých rout nebo hlavních sekcí vašeho UI.
- Poskytněte informativní záložní UI: Záložní UI by mělo informovat uživatele, že došlo k chybě, a případně nabídnout způsob obnovy. Vyhněte se zobrazování obecných chybových zpráv jako "Něco se pokazilo."
- Logujte chyby: Použijte metodu životního cyklu
componentDidCatch
k logování chyb do služby jako Sentry nebo Bugsnag. To vám pomůže sledovat hlavní příčinu problémů a zlepšit stabilitu vaší aplikace. - Nepoužívejte Error Boundaries pro očekávané chyby: Error Boundaries jsou navrženy pro zpracování neočekávaných chyb. Pro očekávané chyby (např. validační chyby, chyby API) použijte specifičtější mechanismy pro zpracování chyb, jako jsou bloky
try...catch
nebo vlastní komponenty pro zpracování chyb. - Zvažte více úrovní Error Boundaries: Můžete vnořovat Error Boundaries, abyste poskytli různé úrovně zpracování chyb. Například můžete mít globální Error Boundary, která zachytí jakékoli nezpracované chyby a zobrazí obecnou chybovou zprávu, a specifičtější Error Boundaries, které zachytí chyby v konkrétních komponentách a zobrazí podrobnější chybové zprávy.
- Nezapomeňte na renderování na straně serveru: Pokud používáte renderování na straně serveru, budete muset zpracovávat chyby i na serveru. Error Boundaries fungují na serveru, ale možná budete muset použít další mechanismy pro zpracování chyb, které se vyskytnou během počátečního renderování.
Pokročilé techniky Error Boundary
1. Použití Render Prop
Místo renderování statického záložního UI můžete použít render prop, abyste získali větší flexibilitu při zpracování chyb. Render prop je prop typu funkce, kterou komponenta používá k renderování obsahu.
class ErrorBoundary extends React.Component {
// ... (stejné jako předtím)
render() {
if (this.state.hasError) {
// Použijte render prop k renderování záložního UI
return this.props.fallbackRender(this.state.error, this.state.errorInfo);
}
return this.props.children;
}
}
function App() {
return (
<ErrorBoundary fallbackRender={(error, errorInfo) => (
<div>
<h2>Něco se pokazilo!</h2>
<p>Chyba: {error.message}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{errorInfo.componentStack}
</details>
</div>
)}>
<MyComponentThatMightThrow/>
</ErrorBoundary>
);
}
To vám umožní přizpůsobit záložní UI pro každou Error Boundary zvlášť. Prop fallbackRender
přijímá chybu a informace o chybě jako argumenty, což vám umožňuje zobrazit specifičtější chybové zprávy nebo provést jiné akce na základě chyby.
2. Error Boundary jako komponenta vyššího řádu (HOC)
Můžete vytvořit komponentu vyššího řádu (HOC), která obalí jinou komponentu pomocí Error Boundary. To může být užitečné pro aplikování Error Boundaries na více komponent, aniž byste museli opakovat stejný kód.
function withErrorBoundary(WrappedComponent) {
return class WithErrorBoundary extends React.Component {
render() {
return (
<ErrorBoundary>
<WrappedComponent {...this.props} />
</ErrorBoundary>
);
}
};
}
// Použití:
const MyComponentWithErrorHandling = withErrorBoundary(MyComponentThatMightThrow);
Funkce withErrorBoundary
přijímá komponentu jako argument a vrací novou komponentu, která obaluje původní komponentu pomocí Error Boundary. To vám umožní snadno přidat zpracování chyb do jakékoli komponenty ve vaší aplikaci.
Testování Error Boundaries
Je důležité testovat vaše Error Boundaries, abyste se ujistili, že fungují správně. K testování Error Boundaries můžete použít testovací knihovny jako Jest a React Testing Library.
Zde je příklad, jak testovat Error Boundary pomocí React Testing Library:
import { render, screen, fireEvent } from '@testing-library/react';
import ErrorBoundary from './ErrorBoundary';
function ComponentThatThrows() {
throw new Error('Tato komponenta vyvolává chybu');
}
test('renders fallback UI when an error is thrown', () => {
render(
<ErrorBoundary>
<ComponentThatThrows />
</ErrorBoundary>
);
expect(screen.getByText('Něco se pokazilo.')).toBeInTheDocument();
});
Tento test renderuje komponentu ComponentThatThrows
, která vyvolá chybu. Test poté ověří, že je zobrazeno záložní UI renderované komponentou Error Boundary.
Error Boundaries a serverové komponenty (React 18+)
S příchodem serverových komponent v Reactu 18 a novějších verzích hrají Error Boundaries nadále klíčovou roli při zpracování chyb. Serverové komponenty se spouštějí na serveru a klientovi posílají pouze vyrenderovaný výstup. Ačkoli základní principy zůstávají stejné, je třeba zvážit několik nuancí:
- Logování chyb na straně serveru: Ujistěte se, že logujete chyby, které se vyskytnou v serverových komponentách, na serveru. To může zahrnovat použití serverového logovacího frameworku nebo odesílání chyb do služby pro sledování chyb.
- Záložní UI na straně klienta: I když se serverové komponenty renderují na serveru, stále musíte poskytnout záložní UI na straně klienta pro případ chyb. To zajišťuje, že uživatel má konzistentní zážitek, i když server selže při renderování komponenty.
- Streamovací SSR: Při použití streamovacího renderování na straně serveru (SSR) se mohou vyskytnout chyby během procesu streamování. Error Boundaries vám mohou pomoci tyto chyby elegantně zpracovat renderováním záložního UI pro postižený stream.
Zpracování chyb v serverových komponentách je vyvíjející se oblast, takže je důležité zůstat v obraze s nejnovějšími osvědčenými postupy a doporučeními.
Běžné chyby, kterým se vyhnout
- Přílišné spoléhání na Error Boundaries: Nepoužívejte Error Boundaries jako náhradu za správné zpracování chyb ve vašich komponentách. Vždy se snažte psát robustní a spolehlivý kód, který chyby zpracovává elegantně.
- Ignorování chyb: Ujistěte se, že logujete chyby zachycené pomocí Error Boundaries, abyste mohli zjistit hlavní příčinu problémů. Nejen zobrazit záložní UI a chybu ignorovat.
- Používání Error Boundaries pro validační chyby: Error Boundaries nejsou správným nástrojem pro zpracování validačních chyb. Místo toho použijte specifičtější validační techniky.
- Netestování Error Boundaries: Testujte své Error Boundaries, abyste se ujistili, že fungují správně.
Závěr
Error Boundaries jsou mocným nástrojem pro tvorbu robustních a spolehlivých React aplikací. Porozuměním tomu, jak efektivně implementovat a používat Error Boundaries, můžete zlepšit uživatelský zážitek, zabránit pádům aplikace a zjednodušit ladění. Nezapomeňte umisťovat Error Boundaries strategicky, poskytovat informativní záložní UI, logovat chyby a důkladně testovat vaše Error Boundaries.
Dodržováním pokynů a osvědčených postupů uvedených v tomto průvodci můžete zajistit, že vaše React aplikace budou odolné vůči chybám a poskytnou pozitivní zážitek vašim uživatelům.