Kattava opas JavaScript Error Boundary -komponenttien ymmärtämiseen ja toteuttamiseen Reactissa vakaan virheidenkäsittelyn ja hallitun käyttöliittymän heikentymisen varmistamiseksi.
JavaScript Error Boundary: Opas virheidenkäsittelyyn Reactissa
React-kehityksessä odottamattomat virheet voivat johtaa turhauttaviin käyttäjäkokemuksiin ja sovelluksen epävakauteen. Hyvin määritelty virheidenkäsittelystrategia on ratkaisevan tärkeä vankkojen ja luotettavien sovellusten rakentamisessa. Reactin Error Boundary -komponentit tarjoavat tehokkaan mekanismin komponenttipuussa esiintyvien virheiden hallittuun käsittelyyn, estäen koko sovelluksen kaatumisen ja mahdollistaen varakäyttöliittymän (fallback UI) näyttämisen.
Mikä on Error Boundary?
Error Boundary on React-komponentti, joka sieppaa JavaScript-virheet missä tahansa sen lapsikomponenttipuussa, kirjaa nämä virheet ja näyttää kaatuneen komponenttipuun sijaan varakäyttöliittymän. Error Boundaryt sieppaavat virheet renderöinnin aikana, elinkaarimetodeissa ja koko alapuolisen puun konstruktoreissa.
Voit ajatella Error Boundarya try...catch
-lohkona React-komponenteille. Aivan kuten try...catch
-lohko mahdollistaa poikkeusten käsittelyn synkronisessa JavaScript-koodissa, Error Boundary mahdollistaa virheiden käsittelyn React-komponenttien renderöinnin aikana.
Tärkeä huomautus: Error Boundaryt eivät sieppaa virheitä:
- Tapahtumankäsittelijöissä (lisätietoja seuraavissa osioissa)
- Asynkronisessa koodissa (esim.
setTimeout
tairequestAnimationFrame
-takaisinkutsut) - Palvelinpuolen renderöinnissä
- Error Boundaryn itsensä aiheuttamissa virheissä (sen lasten sijaan)
Miksi käyttää Error Boundaryja?
Error Boundaryjen käyttäminen tarjoaa useita merkittäviä etuja:
- Parempi käyttäjäkokemus: Sen sijaan, että käyttäjälle näytettäisiin tyhjä valkoinen sivu tai kryptinen virheilmoitus, voit näyttää käyttäjäystävällisen varakäyttöliittymän, joka ilmoittaa käyttäjälle virheestä ja tarjoaa mahdollisesti tavan palautua (esim. sivun uudelleenlataus tai siirtyminen toiseen osioon).
- Sovelluksen vakaus: Error Boundaryt estävät virheitä yhdessä sovelluksen osassa kaatamasta koko sovellusta. Tämä on erityisen tärkeää monimutkaisissa sovelluksissa, joissa on paljon toisiinsa kytkettyjä komponentteja.
- Keskitetty virheidenkäsittely: Error Boundaryt tarjoavat keskitetyn paikan virheiden kirjaamiseen ja ongelmien juurisyyn selvittämiseen. Tämä yksinkertaistaa virheenjäljitystä ja ylläpitoa.
- Hallittu heikentyminen: Voit sijoittaa Error Boundaryja strategisesti eri osiin sovellusta varmistaaksesi, että vaikka jotkut komponentit epäonnistuisivat, muu sovellus pysyy toiminnassa. Tämä mahdollistaa hallitun heikentymisen virhetilanteissa.
Error Boundaryjen toteuttaminen Reactissa
Luodaksesi Error Boundaryn sinun on määriteltävä luokkakomponentti, joka toteuttaa jommankumman (tai molemmat) seuraavista elinkaarimetodeista:
static getDerivedStateFromError(error)
: Tätä elinkaarimetodia kutsutaan sen jälkeen, kun jälkeläiskomponentti on aiheuttanut virheen. Se saa argumenttina aiheutuneen virheen ja sen tulisi palauttaa arvo, jolla päivitetään komponentin tila ilmaisemaan virheen tapahtuminen (esim. asettamallahasError
-lippu arvoontrue
).componentDidCatch(error, info)
: Tätä elinkaarimetodia kutsutaan sen jälkeen, kun jälkeläiskomponentti on aiheuttanut virheen. Se saa argumenttina aiheutuneen virheen sekäinfo
-olion, joka sisältää tietoa siitä, mikä komponentti aiheutti virheen. Voit käyttää tätä metodia virheen kirjaamiseen palveluun, kuten Sentryyn tai Bugsnagiin.
Tässä on perusesimerkki Error Boundary -komponentista:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
error: null,
errorInfo: null
};
}
static getDerivedStateFromError(error) {
// Päivitä tila, jotta seuraava renderöinti näyttää varakäyttöliittymän.
return {
hasError: true,
error: error
};
}
componentDidCatch(error, info) {
// Esimerkki "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
});
// Voit myös kirjata virheen virheraportointipalveluun
//logErrorToMyService(error, info.componentStack);
}
render() {
if (this.state.hasError) {
// Voit renderöidä minkä tahansa mukautetun varakäyttöliittymän
return (
<div>
<h2>Jotain meni pieleen.</h2>
<p>Virhe: {this.state.error ? this.state.error.message : "Tapahtui tuntematon virhe."}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.errorInfo && this.state.errorInfo}
</details>
</div>
);
}
return this.props.children;
}
}
Käyttääksesi Error Boundarya, kääri vain suojattava komponenttipuu sen sisään:
<ErrorBoundary>
<MyComponentThatMightThrow/>
</ErrorBoundary>
Käytännön esimerkkejä Error Boundaryn käytöstä
Käydään läpi joitakin käytännön tilanteita, joissa Error Boundaryt voivat olla erityisen hyödyllisiä:
1. API-virheiden käsittely
Haettaessa dataa API:sta virheitä voi ilmetä verkko-ongelmien, palvelinongelmien tai virheellisen datan vuoksi. Voit kääriä dataa hakevan ja näyttävän komponentin Error Boundarylla käsitelläksesi nämä virheet hallitusti.
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) {
// ErrorBoundary sieppaa virheen
throw error;
} finally {
setIsLoading(false);
}
}
fetchData();
}, []);
if (isLoading) {
return <p>Ladataan käyttäjäprofiilia...</p>;
}
if (!user) {
return <p>Käyttäjätietoja ei saatavilla.</p>;
}
return (
<div>
<h2>{user.name}</h2>
<p>Email: {user.email}</p>
</div>
);
}
function App() {
return (
<ErrorBoundary>
<UserProfile />
</ErrorBoundary>
);
}
Tässä esimerkissä, jos API-kutsu epäonnistuu tai palauttaa virheen, Error Boundary sieppaa virheen ja näyttää varakäyttöliittymän (määritelty Error Boundaryn render
-metodissa). Tämä estää koko sovelluksen kaatumisen ja antaa käyttäjälle informatiivisemman viestin. Voisit laajentaa varakäyttöliittymää tarjoamaan mahdollisuuden yrittää pyyntöä uudelleen.
2. Kolmannen osapuolen kirjastojen virheiden käsittely
Käytettäessä kolmannen osapuolen kirjastoja on mahdollista, että ne aiheuttavat odottamattomia virheitä. Näitä kirjastoja käyttävien komponenttien kääriminen Error Boundaryilla voi auttaa käsittelemään nämä virheet hallitusti.
Kuvitellaan hypoteettinen kaaviokirjasto, joka ajoittain aiheuttaa virheitä dataepäjohdonmukaisuuksien tai muiden ongelmien vuoksi. Voisit kääriä kaaviokomponentin näin:
function MyChartComponent() {
try {
// Renderöi kaavio käyttäen kolmannen osapuolen kirjastoa
return <Chart data={data} />;
} catch (error) {
// Tämä catch-lohko ei ole tehokas React-komponentin elinkaarivirheille
// Se on pääasiassa synkronisille virheille tämän nimenomaisen funktion sisällä.
console.error("Virhe kaavion renderöinnissä:", error);
// Harkitse virheen heittämistä eteenpäin ErrorBoundaryn siepattavaksi
throw error; // Heitetään virhe uudelleen
}
}
function App() {
return (
<ErrorBoundary>
<MyChartComponent />
</ErrorBoundary>
);
}
Jos Chart
-komponentti aiheuttaa virheen, Error Boundary sieppaa sen ja näyttää varakäyttöliittymän. Huomaa, että MyChartComponentin sisällä oleva try/catch sieppaa vain virheet synkronisessa funktiossa, ei komponentin elinkaaressa. Siksi ErrorBoundary on tässä kriittinen.
3. Renderöintivirheiden käsittely
Virheitä voi ilmetä renderöintiprosessin aikana virheellisen datan, väärien prop-tyyppien tai muiden ongelmien vuoksi. Error Boundaryt voivat siepata nämä virheet ja estää sovelluksen kaatumisen.
function DisplayName({ name }) {
if (typeof name !== 'string') {
throw new Error('Nimen on oltava merkkijono');
}
return <h2>Hei, {name}!</h2>;
}
function App() {
return (
<ErrorBoundary>
<DisplayName name={123} /> <!-- Väärä prop-tyyppi -->
</ErrorBoundary>
);
}
Tässä esimerkissä DisplayName
-komponentti odottaa name
-propin olevan merkkijono. Jos sen sijaan annetaan numero, aiheutuu virhe, ja Error Boundary sieppaa sen ja näyttää varakäyttöliittymän.
Error Boundaryt ja tapahtumankäsittelijät
Kuten aiemmin mainittiin, Error Boundaryt eivät sieppaa virheitä, jotka tapahtuvat tapahtumankäsittelijöissä. Tämä johtuu siitä, että tapahtumankäsittelijät ovat tyypillisesti asynkronisia, ja Error Boundaryt sieppaavat vain virheet, jotka tapahtuvat renderöinnin, elinkaarimetodien ja konstruktorien aikana.
Käsitelläksesi virheitä tapahtumankäsittelijöissä, sinun on käytettävä perinteistä try...catch
-lohkoa tapahtumankäsittelijäfunktion sisällä.
function MyComponent() {
const handleClick = () => {
try {
// Koodia, joka saattaa aiheuttaa virheen
throw new Error('Tapahtumankäsittelijässä tapahtui virhe');
} catch (error) {
console.error('Tapahtumankäsittelijässä siepattiin virhe:', error);
// Käsittele virhe (esim. näytä virheilmoitus käyttäjälle)
}
};
return <button onClick={handleClick}>Napsauta minua</button>;
}
Globaali virheidenkäsittely
Vaikka Error Boundaryt ovat erinomaisia virheiden käsittelyyn React-komponenttipuun sisällä, ne eivät kata kaikkia mahdollisia virhetilanteita. Esimerkiksi ne eivät sieppaa virheitä, jotka tapahtuvat React-komponenttien ulkopuolella, kuten globaaleissa tapahtumankuuntelijoissa tai koodissa, joka suoritetaan ennen Reactin alustamista.
Tällaisten virheiden käsittelemiseksi voit käyttää window.onerror
-tapahtumankäsittelijää.
window.onerror = function(message, source, lineno, colno, error) {
console.error('Globaali virheenkäsittelijä:', message, source, lineno, colno, error);
// Kirjaa virhe palveluun, kuten Sentryyn tai Bugsnagiin
// Näytä globaali virheilmoitus käyttäjälle (valinnainen)
return true; // Estä oletusarvoinen virheenkäsittelykäyttäytyminen
};
window.onerror
-tapahtumankäsittelijää kutsutaan aina, kun käsittelemätön JavaScript-virhe tapahtuu. Voit käyttää sitä virheen kirjaamiseen, globaalin virheilmoituksen näyttämiseen käyttäjälle tai muihin toimiin virheen käsittelemiseksi.
Tärkeää: Palauttamalla true
window.onerror
-tapahtumankäsittelijästä estät selaimen näyttämästä oletusvirheilmoitusta. Huomioi kuitenkin käyttäjäkokemus; jos estät oletusviestin, varmista, että tarjoat selkeän ja informatiivisen vaihtoehdon.
Parhaat käytännöt Error Boundaryjen käyttöön
Tässä on joitakin parhaita käytäntöjä, jotka kannattaa pitää mielessä Error Boundaryja käytettäessä:
- Sijoita Error Boundaryt strategisesti: Kääri sovelluksesi eri osia Error Boundaryilla eristääksesi virheet ja estääksesi niiden ketjuuntumisen. Harkitse kokonaisten reittien tai käyttöliittymän suurten osien käärimistä.
- Tarjoa informatiivinen varakäyttöliittymä: Varakäyttöliittymän tulisi ilmoittaa käyttäjälle virheestä ja mahdollisesti tarjota tapa palautua. Vältä yleisten virheilmoitusten, kuten "Jotain meni pieleen", näyttämistä.
- Kirjaa virheet: Käytä
componentDidCatch
-elinkaarimetodia virheiden kirjaamiseen palveluun, kuten Sentryyn tai Bugsnagiin. Tämä auttaa sinua jäljittämään ongelmien juurisyyn ja parantamaan sovelluksesi vakautta. - Älä käytä Error Boundaryja odotettuihin virheisiin: Error Boundaryt on suunniteltu käsittelemään odottamattomia virheitä. Odotettujen virheiden (esim. validointivirheet, API-virheet) osalta käytä tarkempia virheidenkäsittelymekanismeja, kuten
try...catch
-lohkoja tai mukautettuja virheidenkäsittelykomponentteja. - Harkitse useita tasoja Error Boundaryja: Voit sisäkkäistää Error Boundaryja tarjotaksesi eri tasoisia virheidenkäsittelyjä. Esimerkiksi sinulla voi olla globaali Error Boundary, joka sieppaa kaikki käsittelemättömät virheet ja näyttää yleisen virheilmoituksen, sekä tarkempia Error Boundaryja, jotka sieppaavat virheitä tietyissä komponenteissa ja näyttävät yksityiskohtaisempia virheilmoituksia.
- Älä unohda palvelinpuolen renderöintiä: Jos käytät palvelinpuolen renderöintiä, sinun on käsiteltävä virheet myös palvelimella. Error Boundaryt toimivat palvelimella, mutta saatat tarvita lisämekanismeja virheiden sieppaamiseksi, jotka tapahtuvat alkuperäisen renderöinnin aikana.
Edistyneet Error Boundary -tekniikat
1. Render Propin käyttäminen
Sen sijaan, että renderöisit staattisen varakäyttöliittymän, voit käyttää render propia tarjotaksesi enemmän joustavuutta virheiden käsittelyyn. Render prop on funktiomuotoinen prop, jota komponentti käyttää jonkin asian renderöimiseen.
class ErrorBoundary extends React.Component {
// ... (sama kuin aiemmin)
render() {
if (this.state.hasError) {
// Käytä render propia varakäyttöliittymän renderöimiseen
return this.props.fallbackRender(this.state.error, this.state.errorInfo);
}
return this.props.children;
}
}
function App() {
return (
<ErrorBoundary fallbackRender={(error, errorInfo) => (
<div>
<h2>Jotain meni pieleen!</h2>
<p>Virhe: {error.message}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{errorInfo.componentStack}
</details>
</div>
)}>
<MyComponentThatMightThrow/>
</ErrorBoundary>
);
}
Tämä mahdollistaa varakäyttöliittymän mukauttamisen jokaisen Error Boundaryn kohdalla erikseen. fallbackRender
-prop saa argumentteina virheen ja virhetiedot, mikä mahdollistaa tarkempien virheilmoitusten näyttämisen tai muiden toimenpiteiden suorittamisen virheen perusteella.
2. Error Boundary korkeamman asteen komponenttina (HOC)
Voit luoda korkeamman asteen komponentin (HOC), joka käärii toisen komponentin Error Boundarylla. Tämä voi olla hyödyllistä, kun haluat soveltaa Error Boundaryja useisiin komponentteihin toistamatta samaa koodia.
function withErrorBoundary(WrappedComponent) {
return class WithErrorBoundary extends React.Component {
render() {
return (
<ErrorBoundary>
<WrappedComponent {...this.props} />
</ErrorBoundary>
);
}
};
}
// Käyttö:
const MyComponentWithErrorHandling = withErrorBoundary(MyComponentThatMightThrow);
withErrorBoundary
-funktio ottaa argumenttina komponentin ja palauttaa uuden komponentin, joka käärii alkuperäisen komponentin Error Boundarylla. Tämä mahdollistaa virheidenkäsittelyn lisäämisen helposti mihin tahansa sovelluksesi komponenttiin.
Error Boundaryjen testaaminen
On tärkeää testata Error Boundaryt varmistaaksesi, että ne toimivat oikein. Voit käyttää testauskirjastoja, kuten Jestiä ja React Testing Librarya, Error Boundaryjen testaamiseen.
Tässä on esimerkki Error Boundaryn testaamisesta React Testing Librarylla:
import { render, screen, fireEvent } from '@testing-library/react';
import ErrorBoundary from './ErrorBoundary';
function ComponentThatThrows() {
throw new Error('Tämä komponentti aiheuttaa virheen');
}
test('renderöi varakäyttöliittymän, kun virhe aiheutetaan', () => {
render(
<ErrorBoundary>
<ComponentThatThrows />
</ErrorBoundary>
);
expect(screen.getByText('Jotain meni pieleen.')).toBeInTheDocument();
});
Tämä testi renderöi ComponentThatThrows
-komponentin, joka aiheuttaa virheen. Testi varmistaa sitten, että Error Boundaryn renderöimä varakäyttöliittymä tulee näkyviin.
Error Boundaryt ja palvelinkomponentit (React 18+)
React 18:n ja sitä uudempien versioiden myötä esiteltyjen palvelinkomponenttien (Server Components) myötä Error Boundaryt ovat edelleen elintärkeässä roolissa virheidenkäsittelyssä. Palvelinkomponentit suoritetaan palvelimella ja ne lähettävät vain renderöidyn lopputuloksen asiakkaalle. Vaikka ydinperiaatteet pysyvät samoina, on muutamia nyansseja otettava huomioon:
- Palvelinpuolen virheiden kirjaaminen: Varmista, että kirjaat palvelinkomponenteissa tapahtuvat virheet palvelimella. Tämä voi edellyttää palvelinpuolen kirjauskehyksen käyttöä tai virheiden lähettämistä virheenseurantapalveluun.
- Asiakaspuolen varakäyttöliittymä: Vaikka palvelinkomponentit renderöidään palvelimella, sinun on silti tarjottava asiakaspuolen varakäyttöliittymä virhetilanteiden varalta. Tämä varmistaa, että käyttäjällä on yhtenäinen kokemus, vaikka palvelin epäonnistuisi komponentin renderöinnissä.
- Striimaava SSR: Käytettäessä striimaavaa palvelinpuolen renderöintiä (SSR), virheitä voi ilmetä striimausprosessin aikana. Error Boundaryt auttavat sinua käsittelemään nämä virheet hallitusti renderöimällä varakäyttöliittymän kyseiselle striimille.
Virheidenkäsittely palvelinkomponenteissa on kehittyvä alue, joten on tärkeää pysyä ajan tasalla uusimmista parhaista käytännöistä ja suosituksista.
Yleiset vältettävät sudenkuopat
- Liiallinen luottamus Error Boundaryihin: Älä käytä Error Boundaryja korvikkeena asianmukaiselle virheidenkäsittelylle komponenteissasi. Pyri aina kirjoittamaan vankkaa ja luotettavaa koodia, joka käsittelee virheet hallitusti.
- Virheiden sivuuttaminen: Varmista, että kirjaat Error Boundaryjen sieppaamat virheet, jotta voit jäljittää ongelmien juurisyyn. Älä vain näytä varakäyttöliittymää ja sivuuta virhettä.
- Error Boundaryjen käyttö validointivirheisiin: Error Boundaryt eivät ole oikea työkalu validointivirheiden käsittelyyn. Käytä sen sijaan tarkoituksenmukaisempia validointitekniikoita.
- Error Boundaryjen testaamatta jättäminen: Testaa Error Boundaryt varmistaaksesi, että ne toimivat oikein.
Yhteenveto
Error Boundaryt ovat tehokas työkalu vankkojen ja luotettavien React-sovellusten rakentamiseen. Ymmärtämällä, miten Error Boundaryja toteutetaan ja käytetään tehokkaasti, voit parantaa käyttäjäkokemusta, estää sovelluksen kaatumisia ja yksinkertaistaa virheenjäljitystä. Muista sijoittaa Error Boundaryt strategisesti, tarjota informatiivinen varakäyttöliittymä, kirjata virheet ja testata Error Boundaryt perusteellisesti.
Noudattamalla tässä oppaassa esitettyjä ohjeita ja parhaita käytäntöjä voit varmistaa, että React-sovelluksesi ovat virheensietokykyisiä ja tarjoavat positiivisen kokemuksen käyttäjillesi.