Saznajte kako učinkovito kategorizirati i rješavati pogreške unutar React Error Boundaryja, poboljšavajući stabilnost aplikacije i korisničko iskustvo.
Kategorizacija pogrešaka unutar React Error Boundaryja: Sveobuhvatan vodič
Rukovanje pogreškama je ključan aspekt izgradnje robusnih i održivih React aplikacija. Iako Reactovi Error Boundaryji pružaju mehanizam za elegantno rukovanje pogreškama koje se javljaju tijekom renderiranja, razumijevanje kako kategorizirati i odgovoriti na različite vrste pogrešaka ključno je za stvaranje uistinu otporne aplikacije. Ovaj vodič istražuje različite pristupe kategorizaciji pogrešaka unutar Error Boundaryja, nudeći praktične primjere i djelotvorne uvide za poboljšanje vaše strategije upravljanja pogreškama.
Što su React Error Boundaryji?
Predstavljeni u Reactu 16, Error Boundaryji su React komponente koje hvataju JavaScript pogreške bilo gdje u svom podstablu komponenti, bilježe te pogreške i prikazuju rezervno korisničko sučelje umjesto da ruše cijelo stablo komponenti. Funkcioniraju slično try...catch bloku, ali za komponente.
Ključne karakteristike Error Boundaryja:
- Rukovanje pogreškama na razini komponente: Izolirajte pogreške unutar specifičnih podstabala komponenti.
- Elegantna degradacija: Spriječite rušenje cijele aplikacije zbog pogreške jedne komponente.
- Kontrolirano rezervno korisničko sučelje: Prikažite korisniku prilagođenu poruku ili alternativni sadržaj kada se pojavi pogreška.
- Bilježenje pogrešaka: Olakšajte praćenje i otklanjanje pogrešaka bilježenjem informacija o pogreškama.
Zašto kategorizirati pogreške u Error Boundaryjima?
Samo hvatanje pogrešaka nije dovoljno. Učinkovito rukovanje pogreškama zahtijeva razumijevanje što je pošlo po zlu i odgovarajući odgovor. Kategorizacija pogrešaka unutar Error Boundaryja nudi nekoliko prednosti:
- Ciljano rukovanje pogreškama: Različite vrste pogrešaka mogu zahtijevati različite odgovore. Na primjer, mrežna pogreška može zahtijevati mehanizam ponovnog pokušaja, dok pogreška provjere valjanosti podataka može zahtijevati ispravak korisničkog unosa.
- Poboljšano korisničko iskustvo: Prikažite informativnije poruke o pogreškama na temelju vrste pogreške. Generička poruka "Nešto je pošlo po zlu" manje je korisna od specifične poruke koja ukazuje na problem s mrežom ili nevažeći unos.
- Poboljšano otklanjanje pogrešaka: Kategorizacija pogrešaka pruža vrijedan kontekst za otklanjanje pogrešaka i identificiranje temeljnog uzroka problema.
- Proaktivno praćenje: Pratite učestalost različitih vrsta pogrešaka kako biste identificirali ponavljajuće probleme i odredili prioritete ispravaka.
- Strateško rezervno korisničko sučelje: Prikažite različita rezervna korisnička sučelja ovisno o pogrešci, pružajući korisniku relevantnije informacije ili radnje.
Pristupi kategorizaciji pogrešaka
Nekoliko tehnika može se primijeniti za kategorizaciju pogrešaka unutar React Error Boundaryja:
1. Korištenje instanceof
Operator instanceof provjerava je li objekt instanca određene klase. To je korisno za kategorizaciju pogrešaka na temelju njihovih ugrađenih ili prilagođenih vrsta pogrešaka.
Primjer:
class NetworkError extends Error {
constructor(message) {
super(message);
this.name = "NetworkError";
}
}
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
class MyErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true, error: error };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.error("Caught error:", error, errorInfo);
this.setState({errorInfo: errorInfo});
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
let errorMessage = "Something went wrong.";
if (this.state.error instanceof NetworkError) {
errorMessage = "A network error occurred. Please check your connection and try again.";
} else if (this.state.error instanceof ValidationError) {
errorMessage = "There was a validation error. Please review your input.";
}
return (
<div>
<h2>Error!</h2>
<p>{errorMessage}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
Objašnjenje:
- Definirane su prilagođene klase
NetworkErroriValidationError, koje proširuju ugrađenu klasuError. - U metodi
renderkomponenteMyErrorBoundary, operatorinstanceofkoristi se za provjeru vrste uhvaćene pogreške. - Na temelju vrste pogreške, u rezervnom korisničkom sučelju prikazuje se specifična poruka o pogrešci.
2. Korištenje kodova pogrešaka ili svojstava
Drugi pristup je uključivanje kodova pogrešaka ili svojstava unutar samog objekta pogreške. To omogućuje precizniju kategorizaciju na temelju specifičnih scenarija pogrešaka.
Primjer:
function fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => {
if (!response.ok) {
const error = new Error("Network request failed");
error.code = response.status; // Add a custom error code
reject(error);
}
return response.json();
})
.then(data => resolve(data))
.catch(error => reject(error));
});
}
class MyErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true, error: error };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.error("Caught error:", error, errorInfo);
this.setState({errorInfo: errorInfo});
}
render() {
if (this.state.hasError) {
let errorMessage = "Something went wrong.";
if (this.state.error.code === 404) {
errorMessage = "Resource not found.";
} else if (this.state.error.code >= 500) {
errorMessage = "Server error. Please try again later.";
}
return (
<div>
<h2>Error!</h2>
<p>{errorMessage}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
Objašnjenje:
- Funkcija
fetchDatadodaje svojstvocodeobjektu pogreške, predstavljajući HTTP statusni kod. - Komponenta
MyErrorBoundaryprovjerava svojstvocodekako bi odredila specifični scenarij pogreške. - Različite poruke o pogreškama prikazuju se na temelju koda pogreške.
3. Korištenje centraliziranog mapiranja pogrešaka
Za složene aplikacije, održavanje centraliziranog mapiranja pogrešaka može poboljšati organizaciju koda i održivost. To uključuje stvaranje rječnika ili objekta koji preslikava vrste ili kodove pogrešaka u specifične poruke o pogreškama i logiku rukovanja.
Primjer:
const errorMap = {
"NETWORK_ERROR": {
message: "A network error occurred. Please check your connection.",
retry: true,
},
"INVALID_INPUT": {
message: "Invalid input. Please review your data.",
retry: false,
},
404: {
message: "Resource not found.",
retry: false,
},
500: {
message: "Server error. Please try again later.",
retry: true,
},
"DEFAULT": {
message: "Something went wrong.",
retry: false,
},
};
function handleCustomError(errorType) {
const errorDetails = errorMap[errorType] || errorMap["DEFAULT"];
return errorDetails;
}
class MyErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, errorDetails: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
const errorDetails = handleCustomError(error.message);
return { hasError: true, errorDetails: errorDetails };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.error("Caught error:", error, errorInfo);
this.setState({errorInfo: errorInfo});
}
render() {
if (this.state.hasError) {
const { message } = this.state.errorDetails;
return (
<div>
<h2>Error!</h2>
<p>{message}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.errorDetails.message}<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
function MyComponent(){
const [data, setData] = React.useState(null);
React.useEffect(() => {
try {
throw new Error("NETWORK_ERROR");
} catch (e) {
throw e;
}
}, []);
return <div></div>;
}
Objašnjenje:
- Objekt
errorMappohranjuje informacije o pogreškama, uključujući poruke i oznake za ponovni pokušaj, na temelju vrsta ili kodova pogrešaka. - Funkcija
handleCustomErrordohvaća detalje o pogrešci izerrorMapna temelju poruke o pogrešci i vraća zadane vrijednosti ako nije pronađen specifičan kod. - Komponenta
MyErrorBoundarykoristihandleCustomErrorza dobivanje odgovarajuće poruke o pogrešci izerrorMap.
Najbolje prakse za kategorizaciju pogrešaka
- Definirajte jasne vrste pogrešaka: Uspostavite dosljedan skup vrsta pogrešaka ili kodova za svoju aplikaciju.
- Pružite kontekstualne informacije: Uključite relevantne detalje u objekte pogrešaka kako biste olakšali otklanjanje pogrešaka.
- Centralizirajte logiku rukovanja pogreškama: Koristite centralizirano mapiranje pogrešaka ili pomoćne funkcije za dosljedno upravljanje rukovanjem pogreškama.
- Učinkovito bilježite pogreške: Integrirajte se s uslugama za izvještavanje o pogreškama kako biste pratili i analizirali pogreške u produkciji. Popularne usluge uključuju Sentry, Rollbar i Bugsnag.
- Testirajte rukovanje pogreškama: Napišite jedinične testove kako biste provjerili da vaši Error Boundaryji ispravno rukuju različitim vrstama pogrešaka.
- Uzmite u obzir korisničko iskustvo: Prikazujte informativne i korisnicima prilagođene poruke o pogreškama koje vode korisnike prema rješenju. Izbjegavajte tehnički žargon.
- Pratite stope pogrešaka: Pratite učestalost različitih vrsta pogrešaka kako biste identificirali ponavljajuće probleme i odredili prioritete ispravaka.
- Internacionalizacija (i18n): Kada korisniku predstavljate poruke o pogreškama, osigurajte da su vaše poruke pravilno internacionalizirane kako bi podržale različite jezike i kulture. Koristite biblioteke poput
i18nextili Reactov Context API za upravljanje prijevodima. - Pristupačnost (a11y): Pobrinite se da vaše poruke o pogreškama budu pristupačne korisnicima s invaliditetom. Koristite ARIA atribute kako biste pružili dodatni kontekst čitačima zaslona.
- Sigurnost: Budite oprezni s informacijama koje prikazujete u porukama o pogreškama, posebno u produkcijskim okruženjima. Izbjegavajte izlaganje osjetljivih podataka koje bi napadači mogli iskoristiti. Na primjer, nemojte prikazivati sirove tragove staka krajnjim korisnicima.
Primjer scenarija: Rukovanje API pogreškama u aplikaciji za e-trgovinu
Razmotrite aplikaciju za e-trgovinu koja dohvaća informacije o proizvodima s API-ja. Potencijalni scenariji pogrešaka uključuju:
- Mrežne pogreške: API poslužitelj je nedostupan ili je prekinuta korisnička internetska veza.
- Pogreške autentifikacije: Korisnikov autentifikacijski token je nevažeći ili istekao.
- Pogreške resursa nije pronađen: Traženi proizvod ne postoji.
- Pogreške poslužitelja: API poslužitelj naiđe na internu pogrešku.
Koristeći Error Boundaryje i kategorizaciju pogrešaka, aplikacija može elegantno rukovati ovim scenarijima:
// Example (Simplified)
async function fetchProduct(productId) {
try {
const response = await fetch(`/api/products/${productId}`);
if (!response.ok) {
if (response.status === 404) {
throw new Error("PRODUCT_NOT_FOUND");
} else if (response.status === 401 || response.status === 403) {
throw new Error("AUTHENTICATION_ERROR");
} else {
throw new Error("SERVER_ERROR");
}
}
return await response.json();
} catch (error) {
if (error instanceof TypeError && error.message === "Failed to fetch") {
throw new Error("NETWORK_ERROR");
}
throw error;
}
}
class ProductErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, errorDetails: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
const errorDetails = handleCustomError(error.message); // Use errorMap as shown previously
return { hasError: true, errorDetails: errorDetails };
}
componentDidCatch(error, errorInfo) {
console.error("Caught error:", error, errorInfo);
this.setState({errorInfo: errorInfo});
}
render() {
if (this.state.hasError) {
const { message, retry } = this.state.errorDetails;
return (
<div>
<h2>Error!</h2>
<p>{message}</p>
{retry && <button onClick={() => window.location.reload()}>Retry</button>}
</div>
);
}
return this.props.children;
}
}
Objašnjenje:
- Funkcija
fetchProductprovjerava statusni kod API odgovora i baca specifične vrste pogrešaka na temelju statusa. - Komponenta
ProductErrorBoundaryhvata te pogreške i prikazuje odgovarajuće poruke o pogreškama. - Za mrežne pogreške i pogreške poslužitelja, prikazuje se gumb "Pokušaj ponovo", omogućujući korisniku da ponovno pokuša zahtjev.
- Za pogreške autentifikacije, korisnik bi mogao biti preusmjeren na stranicu za prijavu.
- Za pogreške resursa nije pronađen, prikazuje se poruka koja ukazuje da proizvod ne postoji.
Zaključak
Kategorizacija pogrešaka unutar React Error Boundaryja ključna je za izgradnju otpornih aplikacija prilagođenih korisnicima. Primjenom tehnika poput instanceof provjera, kodova pogrešaka i centraliziranog mapiranja pogrešaka, možete učinkovito rukovati različitim scenarijima pogrešaka i pružiti bolje korisničko iskustvo. Ne zaboravite slijediti najbolje prakse za rukovanje pogreškama, bilježenje i testiranje kako biste osigurali da vaša aplikacija elegantno rukuje neočekivanim situacijama.
Implementacijom ovih strategija možete značajno poboljšati stabilnost i održivost vaših React aplikacija, pružajući glatko i pouzdanije iskustvo za vaše korisnike, bez obzira na njihovu lokaciju ili pozadinu.
Dodatni resursi: