به طور کلی، خطاها هنگام ساخت برنامهها اجتنابناپذیر هستند و ممکن است از مشکلات سرور، edge caseها یا بسیاری از دلایل دیگر ناشی شوند. روشهای زیادی برای مدیریت آنها وجود دارد. یکی از این روشها استفاده از error boundaryها در React است. در این مقاله قصد داریم تا مدیریت خطا در React با استفاده از کتابخانه react-error-boundary را بررسی کنیم. تا پایان این مقاله، به درک بهتری از نحوه پیادهسازی error boundaryها در برنامههای React و نحوه مدیریت موثر خطاهای synchronous و asynchronous دست پیدا خواهیم کرد.
Error Boundaryهای React یکی از جنبههای مهم مدیریت خطا در برنامههای React هستند. آنها کامپوننتهای React میباشند که خطاهای جاوااسکریپت را در هر کجای درخت کامپوننت child خود میگیرند، آنها را ثبت میکنند و به جای درخت کامپوننتی که دچار مشکل شده است، یک fallback UI نمایش میدهند. میتوانیم error boundaryها را مانند یک بلاک catch {}
جاوااسکریپت، اما برای کامپوننتها در نظر بگیریم.
ما میتوانیم error boundaryها را در اطراف کل برنامه یا حتی برای کنترل دقیقتر، در اطراف کامپوننتهای جداگانه تنظیم نماییم. باید به این نکته توجه داشته باشیم که error boundaryها در حین رندر شدن در متدهای lifecycle و در constructorهای کل درخت زیر آنها، خطاها را catch میکنند. با این حال، error boundaryها خطاها را برای موارد زیر دریافت نمیکنند:
try/catch
معمولی استفاده کنیم)setTimeout
یا callbackهای requestAnimationFram
)Error Boundaryها در نسخه ۱۶ React معرفی شدند، و برای استفاده از آنها، باید یک کلاس کامپوننت را با یک یا هر دو متد lifecycle زیر تعریف کنیم: getDerivedStateFromError()
یا componentDidCatch()
:
getDerivedStateFromError()
: این متد lifecycle پس از شناسایی خطا، یک fallback UI ارائه میدهد. در مرحله رندر فراخوانی میشود، بنابراین side effectها در آن مجاز نمیباشند.componentDidCatch()
: این متد برای ثبت اطلاعات خطا مورد استفاده قرار میگیرد. در مرحله commit فراخوانی میشود، بنابراین side effectها در آن مجاز هستند.در ادامه یک مثال ساده از یک کلاس کامپوننت داریم که هر دو متد getDerivedStateFromError()
و componentDidCatch()
را پیادهسازی میکند:
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.log(error, errorInfo); } render() { if (this.state.hasError) { // You can render any custom fallback UI return <h1>Something went wrong.</h1>; } return this.props.children; } } // Usage in a component class App extends React.Component { render() { return ( <ErrorBoundary> <MyComponent /> </ErrorBoundary> ); } }
در این مثال، اگر خطایی در MyComponent
ایجاد شود، توسط ErrorBoundary
شناسایی میشود، در کنسول ثبت میگردد و سپس به جای درخت کامپوننتی که خطا را نشان میدهد، پیغام "Something went wrong"
به کاربر نمایش داده میشود.
در حالی که کلاس کامپوننتها و متدهای lifecycle آنها میتوانند به ما در پیادهسازی error boundaryها کمک کنند، اما react-error-boundary کتابخانهای است که این فرآیند را سادهتر و کاربرپسندتر میکند. react-error-boundary یک کتابخانه کوچک است که روشی انعطافپذیر برای مدیریت خطا جاوااسکریپتی در کامپوننتهای React ارائه میدهد.
کتابخانه react-error-boundary از رویکرد مدرنتری همراه با هوکهای React و کامپوننتهای فانکشنال استفاده میکند که با روندهای فعلی در توسعه React هماهنگی بهتری دارد. این کتابخانه از یک کامپوننت ساده به نام ErrorBoundary
استفاده میکند که میتوانیم کدهای احتمالی مستعد خطا را درون آن قرار دهیم.
کامپوننت ErrorBoundary
یک prop به نام fallbackRender
(یا fallbackUI
) دارد که یک تابع یا یک المنت React را میگیرد تا در صورت بروز خطا، آن را به کاربران نمایش دهد. همچنین یک prop resetKeys
ارائه میکند که میتواند برای تنظیم مجدد state کامپوننت در هنگام تغییر المنتهای خاص مورد استفاده قرار بگیرد.
مزیت react-error-boundary این است که نیاز به نوشتن دستی کلاس کامپوننتها و مدیریت state را از بین میبرد و تمام کارهای سنگین را در پشت صحنه انجام میدهد.
اکنون مثالی را بررسی میکنیم تا ببینیم چگونه میتوانیم از react-error-boundary در یک کامپوننت استفاده کنیم:
import { ErrorBoundary } from 'react-error-boundary' function MyFallbackComponent({ error, resetErrorBoundary }) { return ( <div role="alert"> <p>Something went wrong:</p> <pre>{error.message}</pre> <button onClick={resetErrorBoundary}>Try again</button> </div> ) } function MyComponent() { // Some component logic that may throw JS errors } function App() { return ( <ErrorBoundary FallbackComponent={MyFallbackComponent} onReset={() => { // reset the state of your app here }} resetKeys={['someKey']} > <MyComponent /> </ErrorBoundary> ) }
در این مثال، هر زمان که ErrorBoundary
خطایی را دریافت کند، MyFallbackComponent
نمایش داده میشود. این کامپوننت پیغام خطا را نمایش میدهد و دکمهای را برای ریست کردن state خطا و تلاش مجدد کامپوننت ارائه میکند. prop onReset
برای پاک کردن هر گونه side effectای که قبل از ایجاد خطا رخ داده است استفاده میشود، و prop resetKeys
برای کنترل زمانی که state کامپوننت ریست میشود مورد استفاده قرار میگیرد.
ErrorBoundary
همچنین دارای یک prop onError
میباشد، که تابعی است که هر زمان که خطا رخ دهد فراخوانی میشود. میتوانیم از این prop برای ثبت خطاها در یک سرویس گزارش خطا استفاده کنیم. به عنوان مثال:
... // Error logging function function logErrorToService(error, info) { // Use your preferred error logging service console.error("Caught an error:", error, info); } // App component function App() { return ( <ErrorBoundary FallbackComponent={ErrorFallback} onError={logErrorToService}> <MyComponent /> </ErrorBoundary> ); }
یکی از قویترین ویژگیهای کتابخانه react-error-boundary، امکان ریست کردن state مربوط به error boundary است که به معنای پاک کردن خطا و تلاش برای رندر کردن درخت کامپوننت میباشد. هنگامی که یک خطا ممکن است گذرا باشد، مانند یک خطای شبکه که به دلیل قطع موقت رخ میدهد، استفاده از این ویژگی میتواند بسیار مفید باشد.
Error Boundary را میتوانیم با استفاده از تابع resetErrorBoundary
ارائه شده به کامپوننت fallback ریست کنیم. به عنوان مثال، میتوانیم این تابع را در پاسخ به کلیک یک دکمه فراخوانی کنیم و به کاربران اجازه دهیم تا به صورت دستی یک عملیات ناموفق را دوباره امتحان کنند.
ErrorBoundary
همچنین یک تابع onReset
را دریافت میکند، تابعی که درست قبل از تنظیم مجدد state خطا، فراخوانی میشود. این تابع برای انجام هرگونه پاکسازی یا ریست state در برنامه که باید قبل از رندر مجدد پس از یک خطا اتفاق بیفتد، مفید میباشد.
در نهایت، prop resetKeys
آرایهای از مقادیر است که با تغییر آن، ریست کردن error boundary را آغاز میکند. این کار زمانی میتواند مفید باشد که میدانیم با تغییر دادن مقادیر خاص یا مقادیر state، خطا باید برطرف شود. در ادامه مثالی از نحوه استفاده از این propها را بررسی میکنیم:
import { ErrorBoundary } from 'react-error-boundary' function ErrorFallback({ error, resetErrorBoundary }) { return ( <div role="alert"> <p>Something went wrong:</p> <pre>{error.message}</pre> <button onClick={resetErrorBoundary}>Try again</button> </div> ) } function MyComponent({ someKey }) { // Some component logic that may throw JS errors } function App() { const [someKey, setSomeKey] = React.useState(null) return ( <ErrorBoundary FallbackComponent={ErrorFallback} onReset={() => setSomeKey(null)} // reset the state of your app here resetKeys={[someKey]} // reset the error boundary when `someKey` changes > <MyComponent someKey={someKey} /> </ErrorBoundary> ) }
در این مثال، اگر خطایی در MyComponent
مشاهده شود، کامپوننت ErrorFallback
و پیام خطا و دکمه Try again
به کاربران نمایش داده میشود. کاربر با کلیک بر روی این دکمه، resetErrorBoundary
را فراخوانی میکند که تابع onReset
را راهاندازی کرده و state خطا را پاک میکند و در نتیجه MyComponent
دوباره رندر میشود. اگر prop someKey
تغییر کند، error boundary نیز ریست میشود و روشی انعطافپذیر برای بازیابی خطاها بر اساس تغییراتی که در state برنامه صورت میگیرد، ارائه میکند.
هوک useErrorBoundary
یکی دیگر از ویژگیهای مفیدی است که توسط react-error-boundary ارائه میشود. این یک هوک سفارشی است که به ما این امکان را میدهد تا error boundaryها را به راحتی نشان داده و رد کنیم.
استفاده از هوک useErrorBoundary
به ویژه هنگام کار با کدهای asynchronous میتواند مفید باشد. در ادامه مثالی از نحوه استفاده از هوک useErrorBoundary
را بررسی میکنیم:
import { useErrorBoundary } from 'react-error-boundary' function MyComponent() { const { showBoundary } = useErrorBoundary(); async function fetchData() { try { // fetch some data } catch (error) { showBoundary(error); } } return ( ... ); } function App() { return ( <ErrorBoundary FallbackComponent={ErrorFallback}> <MyComponent /> </ErrorBoundary> ); }
در این مثال، MyComponent
از useErrorBoundary
برای دریافت تابعی استفاده میکند که میتواند همراه با خطا فراخوانی شود. تابع fetchData
یک تابع async
است که برخی از دادهها را دریافت میکند و هر گونه خطا را تشخیص میدهد. اگر خطایی رخ دهد، به تابع handleError
منتقل میشود، که خطا را throw میکند تا بتوانیم آن را توسط ErrorBoundary
بگیریم.
useErrorBoundary
یک راه قدرتمند برای رسیدگی به خطاها در کامپوننتهای فانکشنال ارائه میدهد. این هوک به صورت یکپارچه با کامپوننت ErrorBoundary
از کتابخانه react-error-boundary کار میکند و مدیریت خطا در React را به فرآیندی بسیار سادهتر تبدیل مینماید.
همچنین میتوانیم با استفاده از متدی که توسط هوک useErrorBoundary
ارائه میشود، error boundary را ریست کنیم. resetBoundary
error boundary را برای امتحان مجدد رندری که در ابتدا ناموفق بود، درخواست میکند:
import { useErrorBoundary } from "react-error-boundary"; function ErrorFallback({ error }) { const { resetBoundary } = useErrorBoundary(); return ( <div> <p>Something went wrong:</p> <pre>{error.message}</pre> <button onClick={resetBoundary}>Try again</button> </div> ); }
در حالی که هوکهای React و کامپوننتهای فانکشنال به طور فزایندهای محبوب شده و مورد توجه توسعهدهندگان قرار گرفتهاند، اما هنوز موارد زیادی وجود دارد که ممکن است بخواهیم با استفاده از کلاس کامپوننتها کار کنیم یا این که الگوی higher-order component (HOC) را ترجیح دهیم. پکیج react-error-boundary نیز با استفاده از withErrorBoundary
HOC راهحلی برای این موضوع ارائه میدهد.
withErrorBoundary
یک higher-order component است که یک کامپوننت معین را داخل یک error boundary قرار میدهد. این کار میتواند یک روش مفید برای افزودن error boundaryها به کامپوننتهای خود، بدون تغییر پیادهسازی آنها و یا افزودن JSX اضافی به درختان کامپوننتی که داریم باشد. در ادامه نحوه استفاده از withErrorBoundary
را باهم بررسی میکنیم:
import { withErrorBoundary } from 'react-error-boundary' function MyComponent() { // Your component logic } const MyComponentWithErrorBoundary = withErrorBoundary(MyComponent, { FallbackComponent: ErrorFallback, onError: logErrorToService, onReset: handleReset, resetKeys: ['someKey'] }); function App() { return <MyComponentWithErrorBoundary someKey={someKey} /> }
در این مثال، MyComponent
با استفاده از withErrorBoundary
داخل یک error boundary قرار گرفته است. آرگومان دوم برای withErrorBoundary
یک آبجکت options است، که در آن میتوانیم همان مواردی را که برای کامپوننت ErrorBoundary
ارائه میدادیم، تعیین کنیم: FallbackComponent
، onError
، onReset
و resetKeys
.
زمانی ما که میخواهیم error boundaryها را بدون ایجاد تغییری در پیادهسازی آنها به کامپوننتهای خود اضافه کنیم، یا اگر با یک کلاس کامپوننتی کار میکنیم که نمیتواند از هوکها استفاده کند، استفاده از این رویکرد HOC میتواند یک راهحل بسیار مفید باشد. این موضوع، انعطافپذیری react-error-boundary را در تطبیق استایلها و پارادایمهای مختلف کدگذاری در توسعه React نشان میدهد.
کتابخانه react-error-boundary طیف وسیعی از مزایا را ارائه میدهد که آن را به یک راهحل ایدهآل برای مدیریت خطا در برنامههای React تبدیل میکند. در ادامه چند مورد از این مزایای کلیدی را مشاهده میکنیم:
کتابخانه react-error-boundary یک API ساده و شهودی را ارائه میکند که درک و استفاده از آن آسان است. این کتابخانه، پیچیدگیهای مدیریت خطا را از بین میبرد و روشی ساده برای انجام آن به توسعهدهندگان ارائه میدهد.
بر خلاف error boundaryهای سنتی در React، که نیاز به استفاده از کلاس کامپوننتها دارند، react-error-boundary با در نظر گرفتن کامپوننتهای فانکشنال ساخته شده است. این کتابخانه از هوکها استفاده میکند که با روندهای فعلی در توسعه React هماهنگی بیشتری دارد.
کتابخانه react-error-boundary راههای متعددی را برای استفاده از error boundaryها ارائه میدهد، از جمله به عنوان یک کامپوننت، با HOC، یا از طریق یک هوک سفارشی. این تطبیقپذیری به توسعهدهندگان این امکان را میدهد تا بهترین رویکرد را برای نیازها و استایل کدنویسی خود انتخاب کنند.
react-error-boundary اجازه میدهد تا در صورت بروز خطا، یک fallback UI قابل تنظیم نمایش داده شود. این کار میتواند UX بسیار بهتری را نسبت به خراب شدن برنامه یا نمایش صفحه خالی ارائه دهد.
این کتابخانه میتواند state خطا را ریست کند و به برنامه اجازه دهد تا از خطاها بازیابی انجام دهد. این ویژگی به ویژه برای خطاهای گذرا که بدون لود مجدد کامل صفحه قابل حل هستند، بسیار مفید میباشد.
این کتابخانه با استفاده از prop onError
، میتواند خطاها را در یک سرویس گزارش خطا ثبت کرده و اطلاعات ارزشمندی را برای دیباگ کردن و حل مشکلات ارائه نماید.
react-error-boundary به طور فعال نگهداری میشود و به شکل گسترده در جامعه React مورد استفاده قرار میگیرد. بنابراین میتوانیم منتظر به روز رسانیها و بهبودهای منظم باشیم.
یک نکته مهم هنگام اجرای error boundaryها، اطمینان از این است که تمام خطاهای احتمالی در برنامه ما به درستی شناسایی و رسیدگی میشوند. کتابخانه react-error-boundary به این امر کمک کرده و توانایی کشف خطاها را از هر نقطه در درخت کامپوننت فراهم میکند.
این موضوع در مورد اینکه آیا خطاها از متدهای lifecycle یک کلاس کامپوننت، تابع رندر یک کامپوننت فانکشنال یا حتی کد asynchronous هنگام استفاده از هوک useErrorHandler
شناسایی شدهاند، صدق میکند. با این حال، تشخیص خطاها اولین قدم بوده و به اندازه این که میخواهیم تصمیم بگیریم پس از شناسایی خطا چه کاری با آن انجام دهیم، مهم میباشد. اینجاست که مفهوم مکانیسمهای retry مطرح میشود.
مکانیسم retry راهی است که اپلیکیشن ما از آن برای بازیابی خطا استفاده میکند، که این کار را اغلب با تلاش مجدد عملیات ناموفق انجام میدهد.
react-error-boundary از طریق تابع resetErrorBoundary
و prop resetKeys
از مکانیزمهای retry پشتیبانی میکند. میتوانیم resetErrorBoundary
را برای پاک کردن خطا و رندر مجدد درخت کامپوننت فراخوانی کنیم. این کار میتواند به صورت دستی فعال شود، مثلاً در پاسخ به کلیک دکمه، به کاربران اجازه میدهد تا یک عملیات ناموفق را دوباره امتحان کنند.
resetKeys
آرایهای از مقادیر است که با تغییر آن، ریست کردن error boundary را آغاز میکند. این ویژگی به error boundary اجازه میدهد تا بهطور خودکار retry کند، و هنگامی که مقادیر خاص یا مقادیر state تغییر میکنند درخت کامپوننت را رندر نماید. در ادامه مثالی از نحوه پیادهسازی مکانیزم retry با استفاده از react-error-boundary را داریم:
import { ErrorBoundary } from 'react-error-boundary' function ErrorFallback({ error, resetErrorBoundary }) { return ( <div role="alert"> <p>Something went wrong:</p> <pre>{error.message}</pre> <button onClick={resetErrorBoundary}>Try again</button> </div> ) } function MyComponent({ retryCount }) { // Some component logic that may throw JS errors } function App() { const [retryCount, setRetryCount] = React.useState(0) return ( <ErrorBoundary FallbackComponent={ErrorFallback} onReset={() => setRetryCount(retryCount + 1)} // increment the retry count on reset resetKeys={[retryCount]} // reset the error boundary when `retryCount` changes > <MyComponent retryCount={retryCount} /> </ErrorBoundary> ) }
در این مثال، کامپوننت App
state retryCount
را حفظ میکند. هنگامی که بر روی دکمه "Try again"
در کامپوننت ErrorFallback
کلیک میکنیم، resetErrorBoundary
را فراخوانی میکند. سپس onReset
را فعال کرده و پس از آن state خطا را پاک میکند.
onReset
مقدار retryCount
را افزایش میدهد، که پس از آن به دلیل تغییر در resetKeys
، error boundary ریست میشود و در نتیجه MyComponent
دوباره رندر میگردد.
هنگام پیادهسازی error boundaryها در برنامههای React میتوانیم از چندین الگوی طراحی استفاده کنیم. بهترین مورد برای استفاده، به برنامهای که داریم و معماری آن بستگی دارد.
این رویکرد شامل قرار دادن کامپپوننتهای جداگانه در error boundaryها میباشد که سطح بالایی از جزئیات را فراهم میکند و به ما این امکان را میدهد تا خطاهای هر کامپوننت را به صورت جداگانه مدیریت کنیم.
اگر یک کامپوننت دچار مشکل شده باشد، error boundary میتواند خطا را بگیرد و از انتشار آن در درخت کامپوننت جلوگیری نماید. این بدان معنی است که فقط کامپوننت مشکلدار تحت تأثیر قرار میگیرد و بقیه برنامه میتواند به طور عادی به کار خود ادامه دهد.
استفاده از error boundaryهای Component-level مخصوصاً زمانی مفید است که ما کامپوننتهایی در برنامه خود داریم که از یکدیگر جدا شدهاند و state مشترکی ندارند. اگر یکی از کامپوننتها از کار بیفتد، تاثیری بر روی سایر کامپوننتها نمیگذارد. با این حال، اگر بسیاری از کامپوننتها به error boundaryهای خاص خود نیاز داشته باشند، این رویکرد میتواند منجر به ایجاد تکرارهای زیادی شود.
Error Boundaryهای Layout-level در درخت کامپوننت در سطح بالاتر قرار دارند و اغلب گروههایی از کامپوننتهای مرتبط درون آن قرار میگیرند. این گزینه زمانی که ما کامپوننتهای نزدیک به هم داشته باشیم که state مشترک باهم دارند، انتخاب خوبی به شمار میآید.
وقتی خطایی در یک کامپوننت رخ میدهد، error boundary Layout-level میتواند آن را بگیرد و یک پیام خطا یا یک fallback UI برای کل گروه کامپوننتها نمایش دهد. این روش میتواند راه خوبی برای رسیدگی به خطاهایی باشد که بر کل بخش برنامه ما تأثیر میگذارد، مانند نوار sidebar یا داشبورد.
در این روش اگر در یکی از کامپوننتها خطایی ایجاد شود میتواند کل گروه کامپوننتها را تحت تأثیر قرار دهد، حتی اگر سایر کامپوننتها به درستی کار کنند.
error boundaryهای Top-level در بالاترین قسمت درخت کامپوننت قرار میگیرند. آنها یک راه حل جامع هستند که میتوانند هر خطایی که در برنامه ما رخ میدهد را کنترل کنند. این رویکرد تضمین میکند که اگر خطایی در هر جایی از برنامه رخ دهد، میتوانیم آن را بهخوبی شناسایی و مدیریت کنیم.
این رویکرد میتواند از خراب شدن کل برنامه ما در صورت بروز خطا جلوگیری کند. با این حال، یک خطا میتواند بر روی کل برنامه تأثیر بگذارد، نه فقط کامپوننت یا گروهی از کامپوننتهایی که در آنها خطا رخ داده است.
همانطور که در بخشهای قبلی مقاله دیدیم، react-error-boundary خطاهای async را شناسایی نمیکند. این به این دلیل است که کدهای async خارج از رندر اجرا میشوند. هنگامی که خطایی در یک promise یا یک تابع async رخ میدهد، یک promise ریجکت شده را return میکند. کتابخانه react-error-boundary برای شناسایی خطاهای synchronousای که در طول متدهای rendering و lifecycle رخ میدهند طراحی شده است. یعنی خطاهایی را که در مرحله رندر رخ میدهند کنترل میکند، بنابراین خطاهای async را نمیگیرد.
به طور مشابه، توابعی مانند setTimeout
و RequestAnimationFrame
برنامهریزی میکنند تا کدها را پس از تکمیل رندر اجرا کنند، به این معنی که آنها خارج از پشته اجرا، اجرا میشوند و بنابراین گرفتار react-error-boundary نمیشوند.
بنابراین، هنگام وقوع چنین خطاهایی چگونه باید با آنها برخورد کنیم؟ برای رسیدگی به خطاهای async که react-error-boundary نمیتواند آنها شناسایی کند، میتوانیم یک هوک سفارشی ایجاد کنیم که توسط ErrorBoundary
در بلاک catch
async ما فعال میشود. به عنوان مثال:
import React, { useState, useEffect, useCallback } from "react"; import { ErrorBoundary } from "react-error-boundary"; const useAsyncError = () => { const [_, setError] = useState(); return useCallback( (error) => { setError(() => { throw error; }); }, [setError] ); }; const BrokenComponent = () => { const [data, setData] = useState(null); const throwError = useAsyncError(); useEffect(() => { fetch("http://some-site.wtf/rest") .then((res) => res.json()) .then(setData) .catch((e) => { throwError(e); }); }, []); return data; }; export default function App() { return ( <ErrorBoundary fallback={<p>Something went wrong</p>}> <BrokenComponent /> </ErrorBoundary> ); }
هوک سفارشی useAsyncError
هنگامی که خطای async رخ میدهد فراخوانی شده و سپس ErrorBoundary
را trigger میکند. همچنین میتوانیم پیامهای خاصی را در بلاک catch
تعریف کنیم:
.catch((e) => { throwError(new Error("Async Error")); });
از طرف دیگر، react-error-boundary اکنون یک هوک به نام useErrorBoundary
را شامل میشود که میتوانیم از آن برای تشخیص خطاهای async استفاده کنیم:
import React, { useState, useEffect } from "react"; import { ErrorBoundary, useErrorBoundary } from "react-error-boundary"; const BrokenComponent = () => { const [data, setData] = useState(null); const { showBoundary } = useErrorBoundary(); useEffect(() => { fetch("http://some-site.wtf/rest") .then((res) => res.json()) .then(setData) .catch((e) => { showBoundary(e); }); }, []); return data; }; export default function App() { return ( <ErrorBoundary fallback={<p>Something went wrong</p>}> <BrokenComponent /> </ErrorBoundary> ); }
تست برای توسعه نرمافزار یک امر ضروری است و error boundaryهای React نیز از این قاعده مستثنی نیستند. آزمایش صحیح error boundaryها تضمین میکند که آنها به درستی عمل میکنند و خطاها را همانطور که انتظار میرود مدیریت میکنند. میتوانیم از ابزارهای آزمایشی مانند Jest و React Testing Library برای نوشتن تستهای واحد برای error boundaryهای خود استفاده نماییم.
این تستها میتوانند خطاها را در یک کامپوننت شبیهسازی کنند و تأیید نمایند که error boundaryخطا را میگیرد و fallback UI را به درستی ارائه میدهد. به عنوان مثال:
import { render } from "@testing-library/react"; import ErrorBoundary from "../ErrorBoundary"; import ProblematicComponent from "../ProblematicComponent"; it("catches error and renders message", () => { console.error = jest.fn(); render( <ErrorBoundary> <ProblematicComponent /> </ErrorBoundary> ); expect(screen.getByText("Something went wrong.")).toBeInTheDocument(); });
در این تست، <ProblematicComponent />
به گونهای طراحی شده است که عمداً خطا ایجاد کند، و کامپوننت ErrorBoundary
باید خطا را بگیرد و متن Something went wrong
را رندر کند.
ما در این مقاله سعی کردیم مدیریت خطا در React با استفاده از کتابخانه react-error-boundary را بررسی کنیم. این کتابخانه هم کلاس کامپوننتها و هم کامپوننتهای فانکشنال را پوشش میدهد. API منعطف آن، شامل کامپوننتها، کامپوننتهای higher-order و هوکهای سفارشی، راههای مختلفی را برای ادغام مدیریت خطا در کامپوننتهای ما فراهم میکند. علاوه بر این، پشتیبانی آن از fallback UIهای سفارشی، فانکشنالیتی ریست کردن خطا و گزارشدهی خطا به ما کمک میکند که یک UX قدرتمند داشته باشیم.
قرار دادن کتابخانه react-error-boundary در برنامه React میتواند منجر به مدیریت بهتر خطا، دیباگ کردن آسانتر و در نتیجه، محصول نهایی بهتر شود.