Beheers React Error Boundaries voor het bouwen van veerkrachtige en gebruiksvriendelijke applicaties. Leer best practices, implementatietechnieken en geavanceerde strategieën voor foutafhandeling.
React Error Boundaries: Gracieuze technieken voor foutafhandeling voor robuuste applicaties
In de dynamische wereld van webontwikkeling is het creëren van robuuste en gebruiksvriendelijke applicaties van het grootste belang. React, een populaire JavaScript-bibliotheek voor het bouwen van gebruikersinterfaces, biedt een krachtig mechanisme voor het op gracieuze wijze afhandelen van fouten: Error Boundaries. Deze uitgebreide gids duikt in het concept van Error Boundaries en verkent hun doel, implementatie en best practices voor het bouwen van veerkrachtige React-applicaties.
De noodzaak van Error Boundaries begrijpen
React-componenten, zoals alle code, zijn gevoelig voor fouten. Deze fouten kunnen afkomstig zijn van verschillende bronnen, waaronder:
- Onverwachte gegevens: Componenten kunnen gegevens in een onverwacht formaat ontvangen, wat kan leiden tot weergaveproblemen.
- Logische fouten: Bugs in de logica van de component kunnen onverwacht gedrag en fouten veroorzaken.
- Externe afhankelijkheden: Problemen met externe bibliotheken of API's kunnen fouten doorgeven aan uw componenten.
Zonder goede foutafhandeling kan een fout in een React-component de hele applicatie laten crashen, wat resulteert in een slechte gebruikerservaring. Error Boundaries bieden een manier om deze fouten op te vangen en te voorkomen dat ze zich voortplanten in de componentenboom, waardoor wordt gewaarborgd dat de applicatie functioneel blijft, zelfs wanneer afzonderlijke componenten falen.
Wat zijn React Error Boundaries?
Error Boundaries zijn React-componenten die JavaScript-fouten overal in hun kindcomponentenboom opvangen, die fouten loggen en een fallback-UI weergeven in plaats van de componentenboom die is gecrasht. Ze fungeren als een vangnet en voorkomen dat fouten de hele applicatie laten crashen.
Belangrijkste kenmerken van Error Boundaries:
- Alleen klassecomponenten: Error Boundaries moeten worden geïmplementeerd als klassecomponenten. Functionele componenten en hooks kunnen niet worden gebruikt om Error Boundaries te maken.
- Lifecycle-methoden: Ze gebruiken specifieke lifecycle-methoden,
static getDerivedStateFromError()
encomponentDidCatch()
, om fouten af te handelen. - Lokale foutafhandeling: Error Boundaries vangen alleen fouten op in hun kindcomponenten, niet binnen zichzelf.
Error Boundaries implementeren
Laten we de procedure doornemen voor het maken van een basis Error Boundary-component:
1. Het Error Boundary-component maken
Maak eerst een nieuw klassecomponent, bijvoorbeeld met de naam ErrorBoundary
:
import React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false
};
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return {
hasError: true
};
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.error("Caught error: ", error, errorInfo);
// Example: logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return (
<div>
<h2>Er is iets fout gegaan.</h2>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}
<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
Uitleg:
- Constructor: Initialiseert de status van de component met
hasError: false
. static getDerivedStateFromError(error)
: Deze lifecycle-methode wordt aangeroepen nadat een fout is opgetreden door een afstammelingcomponent. Het ontvangt de fout als argument en stelt u in staat de status van de component bij te werken. Hier stellen wehasError
in optrue
om de fallback-UI te activeren. Dit is eenstatic
methode, dus je kuntthis
niet gebruiken in de functie.componentDidCatch(error, errorInfo)
: Deze lifecycle-methode wordt aangeroepen nadat een fout is opgetreden door een afstammelingcomponent. Het ontvangt twee argumenten:error
: De fout die is opgetreden.errorInfo
: Een object met informatie over de componentstack waar de fout is opgetreden. Dit is van onschatbare waarde voor het debuggen.
Binnen deze methode kunt u de fout registreren bij een service zoals Sentry, Rollbar of een aangepaste logoplossing. Vermijd het proberen om de fout direct in deze functie opnieuw weer te geven of op te lossen; het belangrijkste doel is om het probleem te loggen.
render()
: De render-methode controleert de statushasError
. Als dittrue
is, wordt een fallback-UI weergegeven (in dit geval een eenvoudige foutmelding). Anders worden de kinderen van de component weergegeven.
2. De Error Boundary gebruiken
Om de Error Boundary te gebruiken, omwikkelt u gewoon elke component die een fout kan veroorzaken met het ErrorBoundary
-component:
import ErrorBoundary from './ErrorBoundary';
function MyComponent() {
// This component might throw an error
return (
<ErrorBoundary>
<PotentiallyBreakingComponent />
</ErrorBoundary>
);
}
export default MyComponent;
Als PotentiallyBreakingComponent
een fout veroorzaakt, zal de ErrorBoundary
deze opvangen, de fout loggen en de fallback-UI weergeven.
3. Illustratieve voorbeelden met globale context
Overweeg een e-commerce-applicatie die productinformatie weergeeft die is opgehaald van een externe server. Een component, ProductDisplay
, is verantwoordelijk voor het weergeven van productdetails. De server kan echter af en toe onverwachte gegevens retourneren, wat kan leiden tot weergavefouten.
// ProductDisplay.js
import React from 'react';
function ProductDisplay({ product }) {
// Simulate a potential error if product.price is not a number
if (typeof product.price !== 'number') {
throw new Error('Ongeldige productprijs');
}
return (
<div>
<h2>{product.name}</h2>
<p>Prijs: {product.price}</p>
<img src={product.imageUrl} alt={product.name} />
</div>
);
}
export default ProductDisplay;
Om tegen dergelijke fouten te beschermen, omwikkelt u het component ProductDisplay
met een ErrorBoundary
:
// App.js
import React from 'react';
import ErrorBoundary from './ErrorBoundary';
import ProductDisplay from './ProductDisplay';
function App() {
const product = {
name: 'Voorbeeldproduct',
price: 'Geen nummer', // Opzettelijk onjuiste gegevens
imageUrl: 'https://example.com/image.jpg'
};
return (
<div>
<ErrorBoundary>
<ProductDisplay product={product} />
</ErrorBoundary>
</div>
);
}
export default App;
In dit scenario, omdat de product.price
opzettelijk is ingesteld op een tekenreeks in plaats van een getal, veroorzaakt het component ProductDisplay
een fout. De ErrorBoundary
vangt deze fout op, voorkomt dat de hele applicatie crasht en geeft in plaats daarvan de fallback-UI weer in plaats van het defecte component ProductDisplay
.
4. Error Boundaries in geïnternationaliseerde applicaties
Bij het bouwen van applicaties voor een wereldwijd publiek, moeten foutmeldingen worden gelokaliseerd om een betere gebruikerservaring te bieden. Error Boundaries kunnen worden gebruikt in combinatie met internationalisatie (i18n)-bibliotheken om vertaalde foutmeldingen weer te geven.
// ErrorBoundary.js (met i18n-ondersteuning)
import React from 'react';
import { useTranslation } from 'react-i18next'; // Assuming you're using react-i18next
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
error: null,
errorInfo: null,
};
}
static getDerivedStateFromError(error) {
return {
hasError: true,
error: error,
};
}
componentDidCatch(error, errorInfo) {
console.error("Caught error: ", error, errorInfo);
this.setState({errorInfo: errorInfo});
}
render() {
if (this.state.hasError) {
return (
<FallbackUI error={this.state.error} errorInfo={this.state.errorInfo}/>
);
}
return this.props.children;
}
}
const FallbackUI = ({error, errorInfo}) => {
const { t } = useTranslation();
return (
<div>
<h2>{t('error.title')}</h2>
<p>{t('error.message')}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{error && error.toString()}<br />
{errorInfo?.componentStack}
</details>
</div>
);
}
export default ErrorBoundary;
In dit voorbeeld gebruiken we react-i18next
om de fouttitel en het bericht in de fallback-UI te vertalen. De functies t('error.title')
en t('error.message')
halen de juiste vertalingen op op basis van de geselecteerde taal van de gebruiker.
5. Overwegingen voor server-side rendering (SSR)
Bij gebruik van Error Boundaries in server-side rendered applicaties is het cruciaal om fouten correct af te handelen om te voorkomen dat de server crasht. De documentatie van React beveelt aan om Error Boundaries niet te gebruiken om te herstellen van weergavefouten op de server. In plaats daarvan moet u fouten afhandelen voordat u de component weergeeft, of een statische foutpagina op de server weergeven.
Best practices voor het gebruik van Error Boundaries
- Granulaire componenten omwikkelen: Omwikkel individuele componenten of kleine delen van uw applicatie met Error Boundaries. Dit voorkomt dat een enkele fout de hele UI laat crashen. Overweeg om specifieke functies of modules te omwikkelen in plaats van de hele applicatie.
- Fouten registreren: Gebruik de methode
componentDidCatch()
om fouten te registreren bij een bewakingsservice. Dit helpt u bij het volgen en oplossen van problemen in uw applicatie. Services als Sentry, Rollbar en Bugsnag zijn populaire keuzes voor fouttracking en -rapportage. - Informatieve fallback-UI bieden: Geef een gebruiksvriendelijke foutmelding weer in de fallback-UI. Vermijd technische jargon en geef instructies over hoe u verder moet gaan (bijv. de pagina vernieuwen, contact opnemen met support). Geef indien mogelijk alternatieve acties aan die de gebruiker kan uitvoeren.
- Niet overmatig gebruiken: Vermijd het omwikkelen van elke afzonderlijke component met een Error Boundary. Richt u op gebieden waar fouten waarschijnlijker zijn, zoals componenten die gegevens ophalen van externe API's of complexe gebruikersinteracties afhandelen.
- Test Error Boundaries: Zorg ervoor dat uw Error Boundaries correct werken door opzettelijk fouten te genereren in de componenten die ze omwikkelen. Schrijf unit tests of integratietests om te controleren of de fallback-UI wordt weergegeven zoals verwacht en dat fouten correct worden geregistreerd.
- Error Boundaries zijn NIET bedoeld voor:
- Gebeurtenisafhandelaars
- Asynchrone code (bijv.
setTimeout
ofrequestAnimationFrame
callbacks) - Server-side rendering
- Fouten die in de Error Boundary zelf optreden (in plaats van de kinderen)
Geavanceerde strategieën voor foutafhandeling
1. Herhaalmechanismen
In sommige gevallen is het mogelijk om te herstellen van een fout door de bewerking die de fout veroorzaakte opnieuw uit te voeren. Als bijvoorbeeld een netwerkaanvraag mislukt, kunt u deze na een korte vertraging opnieuw proberen. Error Boundaries kunnen worden gecombineerd met herhaalmechanismen om een meer veerkrachtige gebruikerservaring te bieden.
// ErrorBoundaryWithRetry.js
import React from 'react';
class ErrorBoundaryWithRetry extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
retryCount: 0,
};
}
static getDerivedStateFromError(error) {
return {
hasError: true,
};
}
componentDidCatch(error, errorInfo) {
console.error("Caught error: ", error, errorInfo);
}
handleRetry = () => {
this.setState(prevState => ({
hasError: false,
retryCount: prevState.retryCount + 1,
}), () => {
// This forces the component to re-render. Consider better patterns with controlled props.
this.forceUpdate(); // WARNING: Use with caution
if (this.props.onRetry) {
this.props.onRetry();
}
});
};
render() {
if (this.state.hasError) {
return (
<div>
<h2>Er is iets fout gegaan.</h2>
<button onClick={this.handleRetry}>Opnieuw proberen</button>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundaryWithRetry;
Het component ErrorBoundaryWithRetry
bevat een knop voor opnieuw proberen die, wanneer erop wordt geklikt, de status hasError
reset en de kindcomponenten opnieuw weergeeft. U kunt ook een retryCount
toevoegen om het aantal keren te beperken dat opnieuw wordt geprobeerd. Deze aanpak kan vooral nuttig zijn voor het afhandelen van tijdelijke fouten, zoals tijdelijke netwerkstoringen. Zorg ervoor dat de `onRetry`-prop correct wordt afgehandeld en de logica die mogelijk fouten heeft veroorzaakt opnieuw ophaalt/uitvoert.
2. Feature flags
Met feature flags kunt u functies in uw applicatie dynamisch in- of uitschakelen, zonder nieuwe code te implementeren. Error Boundaries kunnen worden gebruikt in combinatie met feature flags om de functionaliteit op gracieuze wijze te degraderen in het geval van een fout. Als bijvoorbeeld een bepaalde functie fouten veroorzaakt, kunt u deze uitschakelen met behulp van een feature flag en een bericht aan de gebruiker weergeven dat aangeeft dat de functie tijdelijk niet beschikbaar is.
3. Circuit breaker-patroon
Het circuit breaker-patroon is een softwareontwerppatroon dat wordt gebruikt om te voorkomen dat een applicatie herhaaldelijk probeert een bewerking uit te voeren die waarschijnlijk mislukt. Het werkt door de succes- en faalfrequenties van een bewerking te bewaken en, als de faalfrequentie een bepaalde drempel overschrijdt, 'het circuit te openen' en verdere pogingen om de bewerking uit te voeren gedurende een bepaalde periode te voorkomen. Dit kan helpen cascadefouten te voorkomen en de algehele stabiliteit van de applicatie te verbeteren.
Error Boundaries kunnen worden gebruikt om het circuit breaker-patroon te implementeren in React-applicaties. Wanneer een Error Boundary een fout opvangt, kan het een foutteller verhogen. Als de foutteller een drempel overschrijdt, kan de Error Boundary een bericht aan de gebruiker weergeven dat aangeeft dat de functie tijdelijk niet beschikbaar is en verdere pogingen om de bewerking uit te voeren voorkomen. Na een bepaalde periode kan de Error Boundary 'het circuit sluiten' en pogingen om de bewerking opnieuw uit te voeren weer toestaan.
Conclusie
React Error Boundaries zijn een essentieel hulpmiddel voor het bouwen van robuuste en gebruiksvriendelijke applicaties. Door Error Boundaries te implementeren, kunt u voorkomen dat fouten uw hele applicatie laten crashen, uw gebruikers een gracieuze fallback-UI bieden en fouten registreren bij bewakingsservices voor het debuggen en analyseren. Door de best practices en geavanceerde strategieën in deze gids te volgen, kunt u React-applicaties bouwen die veerkrachtig en betrouwbaar zijn en een positieve gebruikerservaring bieden, zelfs in het geval van onverwachte fouten. Vergeet niet om u te concentreren op het leveren van behulpzame foutberichten die zijn gelokaliseerd voor een wereldwijd publiek.