Polski

Dowiedz się, jak implementować React Error Boundaries, aby elegancko obsługiwać błędy, zapobiegać awariom aplikacji i poprawiać doświadczenia użytkownika. Poznaj najlepsze praktyki, zaawansowane techniki i przykłady z życia wzięte.

React Error Boundaries: Kompleksowy przewodnik po solidnym zarządzaniu błędami

W świecie nowoczesnego tworzenia aplikacji internetowych, płynne i niezawodne doświadczenie użytkownika jest najważniejsze. Pojedynczy, nieobsłużony błąd może spowodować awarię całej aplikacji React, pozostawiając użytkowników sfrustrowanych i potencjalnie prowadząc do utraty cennych danych. React Error Boundaries dostarczają potężnego mechanizmu do eleganckiego obsługiwania tych błędów, zapobiegania katastrofalnym awariom i oferowania bardziej odpornego i przyjaznego dla użytkownika doświadczenia. Ten przewodnik przedstawia kompleksowy przegląd React Error Boundaries, omawiając ich cel, implementację, najlepsze praktyki i zaawansowane techniki.

Czym są React Error Boundaries?

Error Boundaries to komponenty React, które przechwytują błędy JavaScript w dowolnym miejscu w drzewie komponentów potomnych, logują te błędy i wyświetlają interfejs zastępczy (fallback UI) zamiast drzewa komponentów, które uległo awarii. Działają jak siatka bezpieczeństwa, zapobiegając sytuacji, w której błędy w jednej części aplikacji powodują awarię całego interfejsu użytkownika. Wprowadzone w React 16, Error Boundaries zastąpiły wcześniejsze, mniej solidne mechanizmy obsługi błędów.

Można myśleć o Error Boundaries jak o blokach `try...catch` dla komponentów React. Jednak w przeciwieństwie do `try...catch`, działają one na poziomie komponentów, zapewniając deklaratywny i reużywalny sposób obsługi błędów w całej aplikacji.

Dlaczego warto używać Error Boundaries?

Error Boundaries oferują kilka kluczowych korzyści:

Tworzenie komponentu Error Boundary

Aby utworzyć komponent Error Boundary, należy zdefiniować komponent klasowy, który implementuje jedną lub obie z następujących metod cyklu życia:

Oto podstawowy przykład komponentu Error Boundary:


class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Zaktualizuj stan, aby następne renderowanie pokazało interfejs zastępczy.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // Przykładowy "componentStack":
    //   in ComponentThatThrows (created by App)
    //   in App
    console.error("Złapano błąd: ", error, info.componentStack);
    // Możesz również zalogować błąd do serwisu raportowania błędów
    // logErrorToMyService(error, info.componentStack);
  }

  render() {
    if (this.state.hasError) {
      // Możesz wyrenderować dowolny niestandardowy interfejs zastępczy
      return 

Coś poszło nie tak.

; } return this.props.children; } }

Wyjaśnienie:

Używanie Error Boundaries

Aby użyć Error Boundary, wystarczy opakować komponent lub komponenty, które chcesz chronić, komponentem ErrorBoundary:



  


Jeśli ComponentThatMightThrow rzuci błąd, ErrorBoundary przechwyci go, zaktualizuje swój stan i wyrenderuje interfejs zastępczy. Reszta aplikacji będzie nadal działać normalnie.

Umiejscowienie Error Boundary

Umiejscowienie Error Boundaries jest kluczowe dla skutecznej obsługi błędów. Rozważ następujące strategie:

Przykład:


function App() {
  return (
    
); }

W tym przykładzie każda główna sekcja aplikacji (Header, Sidebar, ContentArea, Footer) jest opakowana w Error Boundary. Pozwala to każdej sekcji na niezależne obsługiwanie błędów, zapobiegając wpływowi pojedynczego błędu na całą aplikację.

Dostosowywanie interfejsu zastępczego (Fallback UI)

Interfejs zastępczy wyświetlany przez Error Boundary powinien być informacyjny i przyjazny dla użytkownika. Rozważ następujące wytyczne:

Przykład:


class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Zaktualizuj stan, aby następne renderowanie pokazało interfejs zastępczy.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // Możesz również zalogować błąd do serwisu raportowania błędów
    console.error("Złapano błąd: ", error, info.componentStack);
  }

  render() {
    if (this.state.hasError) {
      // Możesz wyrenderować dowolny niestandardowy interfejs zastępczy
      return (
        

Ups! Coś poszło nie tak.

Przepraszamy, wystąpił błąd podczas próby wyświetlenia tej zawartości.

Spróbuj odświeżyć stronę lub skontaktuj się z pomocą techniczną, jeśli problem będzie się powtarzał.

Skontaktuj się z pomocą
); } return this.props.children; } }

Ten przykład wyświetla bardziej informacyjny interfejs zastępczy, który zawiera jasny komunikat o błędzie, sugerowane rozwiązania oraz linki do odświeżenia strony i skontaktowania się z pomocą techniczną.

Obsługa różnych typów błędów

Error Boundaries przechwytują błędy, które występują podczas renderowania, w metodach cyklu życia oraz w konstruktorach całego drzewa poniżej nich. *Nie przechwytują* one błędów dla:

Aby obsłużyć te typy błędów, należy użyć innych technik.

Obsługa zdarzeń

Dla błędów występujących w obsłudze zdarzeń, użyj standardowego bloku try...catch:


function MyComponent() {
  const handleClick = () => {
    try {
      // Kod, który może rzucić błąd
      throw new Error("Coś poszło nie tak w obsłudze zdarzenia");
    } catch (error) {
      console.error("Błąd w obsłudze zdarzenia: ", error);
      // Obsłuż błąd (np. wyświetl komunikat o błędzie)
      alert("Wystąpił błąd. Spróbuj ponownie.");
    }
  };

  return ;
}

Kod asynchroniczny

Dla błędów występujących w kodzie asynchronicznym, użyj bloków try...catch wewnątrz funkcji asynchronicznej:


function MyComponent() {
  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch("https://api.example.com/data");
        const data = await response.json();
        // Przetwórz dane
        console.log(data);
      } catch (error) {
        console.error("Błąd podczas pobierania danych: ", error);
        // Obsłuż błąd (np. wyświetl komunikat o błędzie)
        alert("Pobieranie danych nie powiodło się. Spróbuj ponownie później.");
      }
    }

    fetchData();
  }, []);

  return 
Ładowanie danych...
; }

Alternatywnie, można użyć globalnego mechanizmu obsługi błędów dla nieobsłużonych odrzuceń obietnic (promise rejections):


window.addEventListener('unhandledrejection', function(event) {
  console.error('Nieobsłużone odrzucenie (obietnica: ', event.promise, ', powód: ', event.reason, ');');
  // Opcjonalnie wyświetl globalny komunikat o błędzie lub zaloguj błąd do serwisu
  alert("Wystąpił nieoczekiwany błąd. Spróbuj ponownie później.");
});

Zaawansowane techniki Error Boundary

Resetowanie Error Boundary

W niektórych przypadkach możesz chcieć zapewnić użytkownikom sposób na zresetowanie Error Boundary i ponowienie operacji, która spowodowała błąd. Może to być przydatne, jeśli błąd był spowodowany tymczasowym problemem, takim jak problem z siecią.

Aby zresetować Error Boundary, można użyć biblioteki do zarządzania stanem, takiej jak Redux lub Context, aby zarządzać stanem błędu i zapewnić funkcję resetowania. Alternatywnie, można użyć prostszego podejścia, wymuszając ponowne zamontowanie Error Boundary.

Przykład (Wymuszenie ponownego montowania):


class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, errorCount: 0, key: 0 };
  }

  static getDerivedStateFromError(error) {
    // Zaktualizuj stan, aby następne renderowanie pokazało interfejs zastępczy.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // Możesz również zalogować błąd do serwisu raportowania błędów
    console.error("Złapano błąd: ", error, info.componentStack);
    this.setState(prevState => ({ errorCount: prevState.errorCount + 1 }));
  }

  resetError = () => {
      this.setState({hasError: false, key: this.state.key + 1})
  }

  render() {
    if (this.state.hasError) {
      // Możesz wyrenderować dowolny niestandardowy interfejs zastępczy
      return (
        

Ups! Coś poszło nie tak.

Przepraszamy, wystąpił błąd podczas próby wyświetlenia tej zawartości.

); } return
{this.props.children}
; } }

W tym przykładzie do otaczającego diva dodano atrybut 'key'. Zmiana klucza zmusza komponent do ponownego zamontowania, skutecznie czyszcząc stan błędu. Metoda `resetError` aktualizuje stan `key` komponentu, powodując jego ponowne zamontowanie i wyrenderowanie jego dzieci.

Używanie Error Boundaries z Suspense

React Suspense pozwala "zawiesić" renderowanie komponentu do czasu spełnienia określonego warunku (np. pobrania danych). Można połączyć Error Boundaries z Suspense, aby zapewnić bardziej solidną obsługę błędów dla operacji asynchronicznych.


import React, { Suspense } from 'react';

function MyComponent() {
  return (
    
      Ładowanie...
}> ); } function DataFetchingComponent() { const data = useData(); // Niestandardowy hook, który asynchronicznie pobiera dane return
{data.value}
; }

W tym przykładzie komponent DataFetchingComponent pobiera dane asynchronicznie za pomocą niestandardowego hooka. Komponent Suspense wyświetla wskaźnik ładowania podczas pobierania danych. Jeśli podczas procesu pobierania danych wystąpi błąd, ErrorBoundary przechwyci go i wyświetli interfejs zastępczy.

Najlepsze praktyki dla React Error Boundaries

Przykłady z życia wzięte

Oto kilka przykładów z życia wziętych, jak można wykorzystać Error Boundaries:

Alternatywy dla Error Boundaries

Chociaż Error Boundaries są zalecanym sposobem obsługi błędów w React, istnieją pewne alternatywne podejścia, które można rozważyć. Jednak, należy pamiętać, że te alternatywy mogą nie być tak skuteczne jak Error Boundaries w zapobieganiu awariom aplikacji i zapewnianiu płynnego doświadczenia użytkownika.

Ostatecznie, Error Boundaries zapewniają solidne i ustandaryzowane podejście do obsługi błędów w React, co czyni je preferowanym wyborem w większości przypadków użycia.

Podsumowanie

React Error Boundaries są niezbędnym narzędziem do budowania solidnych i przyjaznych dla użytkownika aplikacji React. Przechwytując błędy i wyświetlając interfejsy zastępcze, zapobiegają awariom aplikacji, poprawiają doświadczenie użytkownika i upraszczają debugowanie błędów. Postępując zgodnie z najlepszymi praktykami opisanymi w tym przewodniku, można skutecznie wdrożyć Error Boundaries w swoich aplikacjach i stworzyć bardziej odporne i niezawodne doświadczenie dla użytkowników na całym świecie.