Platform
    • Memoization
    • Error Boundaries
Projects
  • API Connections & Tools
  1. Documentation
  2. Documentation

Error Boundary

Изоляция ошибок пользовательского интерфейса и обеспечение стабильности приложения.

Стандарты изоляции ошибок

Принципы: Изоляция сбоев позволяет приложению продолжать работу даже при падении отдельного виджета или фичи.

Иерархическое дерево надежности

Когда использовать

  • Изоляция падений:

    Виджеты, внешние компоненты, сложные UI-блоки, Lazy-loaded компоненты и интеграции (чаты, карты).

  • Границы слоев:

    Page-level (вся страница) и Feature-level (отдельный блок: корзина, чат, аналитика).

  • Динамический код:

    Когда код может быть нестабилен или подключается сторонний модуль.

01Реализация ErrorBoundary

Базовый класс для перехвата ошибок:

shared/ui/error-boundary/error-boundary.tsx
1"use client"; 2 3import { Component, type ErrorInfo, type ReactNode } from "react"; 4 5export interface IErrorBoundaryProps { 6 children?: ReactNode; 7 fallback?: ReactNode; 8 /** Отправка в логгер / мониторинг (Sentry и т.п.), а не вывод в консоль */ 9 onError?: (error: Error, errorInfo: ErrorInfo) => void; 10} 11 12interface IErrorBoundaryState { 13 hasError: boolean; 14 error: Error | null; 15} 16 17/** Fallback по умолчанию: сообщение + стек для отладки */ 18const DefaultErrorUI = ({ error }: { error: Error | null }) => ( 19 <div 20 role="alert" 21 className="p-4 rounded-lg flex flex-col items-start gap-2 border border-destructive/50 bg-destructive/10 text-destructive font-mono text-sm max-w-full overflow-x-auto" 22 > 23 <span className="font-bold"> 24 An error occurred while rendering this component. 25 </span> 26 <details className="mt-2 w-full"> 27 <summary className="cursor-pointer font-semibold opacity-80 hover:opacity-100"> 28 {error?.message || "Error"} 29 </summary> 30 <pre className="mt-2 text-xs opacity-70 whitespace-pre-wrap"> 31 {error?.stack} 32 </pre> 33 </details> 34 </div> 35); 36 37export class ErrorBoundary extends Component< 38 IErrorBoundaryProps, 39 IErrorBoundaryState 40> { 41 public state: IErrorBoundaryState = { 42 hasError: false, 43 error: null 44 }; 45 46 public static getDerivedStateFromError(error: Error): IErrorBoundaryState { 47 return { hasError: true, error }; 48 } 49 50 public componentDidCatch(error: Error, errorInfo: ErrorInfo) { 51 this.props.onError?.(error, errorInfo); 52 } 53 54 public render() { 55 if (this.state.hasError) { 56 return this.props.fallback ?? <DefaultErrorUI error={this.state.error} />; 57 } 58 return this.props.children; 59 } 60}

02Реализация withErrorBoundary

HOC для оборачивания компонентов:

shared/ui/error-boundary/with-error-boundary.tsx
1import React, { ComponentType } from "react"; 2import { ErrorBoundary } from "./error-boundary"; 3 4export function withErrorBoundary<P extends object>( 5 Component: ComponentType<P>, 6 fallback?: React.ReactNode 7) { 8 return function WithErrorBoundary(props: P) { 9 return ( 10 <ErrorBoundary fallback={fallback}> 11 <Component {...props} /> 12 </ErrorBoundary> 13 ); 14 }; 15}

03Пример использования HOC

Практический пример изоляции фичи с помощью withErrorBoundary. Обратите внимание на то, как HOC предотвращает "белый экран" при ошибках в нестабильной логике рендеринга дочерних компонентов.

HOC Usage Example
1import { withErrorBoundary } from "@/shared/ui"; 2 3function UserProfileWidget({ userId }: { userId: string }) { 4 const { data, isLoading } = useGetUserProfileQuery(userId); 5 6 if (isLoading) return <SkeletonProfile />; 7 8 const formattedStats = data.stats.map(stat => ({ 9 ...stat, 10 value: (stat.raw / stat.total) * 100 11 })); 12 13 return ( 14 <div className="flex flex-col gap-4"> 15 <UserProfileAvatar user={data.user} /> 16 <UserProfileStats stats={formattedStats} /> 17 </div> 18 ); 19} 20 21export const UserProfile = withErrorBoundary(UserProfileWidget, <UserProfileErrorUI />);