Error Boundary کامپوننت React است که خطاهای JavaScript را در درخت کامپوننتهای فرزند خود میگیرد و به جای صفحه crash یک رابط جایگزین نمایش میدهد. در زمینه React Native از سقوط کامل برنامه در خطاهای غیربحرانی رندر جلوگیری میکند. طبق React Documentation, 2024، error boundary خطاها را در متدهای render، lifecycle-hookها و سازندههای کامپوننتهای فرزند میگیرد و به برنامه اجازه ادامه کار میدهد. در React Native این امر بسیار حیاتی است، زیرا برنامه موبایل با F5 بارگذاری مجدد نمیشود — کاربر کل نشست خود را از دست میدهد.
نکات اصلی
Error Boundary مکانیزم React برای تنزل تدریجی (graceful degradation) در خطاهای رندر است. در React 16 (2017) به عنوان کامپوننت wrapper معرفی شد که یکی از دو متد چرخه حیات را پیادهسازی میکند: static getDerivedStateFromError یا componentDidCatch. Error Boundary به کاربر اجازه میدهد به جای صفحه سفید خالی یا سقوط کامل برنامه، یک پیام معنادار ببیند.
پیش از React 16، هر خطای مدیریتنشده در render منجر به سقوط کل برنامه با حذف کل درخت DOM میشد. در برنامههای وب این به معنای صفحه سفید خالی و در React Native سقوط کامل برنامه با بازگشت به صفحه اصلی بود. تیم React Error Boundary را به عنوان معادل catch-block برای UI اعلامی معرفی کرد و این مفهوم را از رویکرد «بگذار سقوط کند» در زبان Erlang به عاریت گرفت.
در React Native نبود Error Boundary به معنای سقوط کامل برنامه در هر خطای رندر است. کاربر کل نشست جاری خود را بدون امکان بازیابی از دست میدهد. Error Boundary در React Native حیاتی است، زیرا برنامههای موبایل مانند صفحات وب بارگذاری مجدد نمیشوند — نشست کاربر به طور جبرانناپذیری از دست میرود و کاربر باید همه چیز را از نو شروع کند.
Error Boundary در سطح درخت React کار میکند. وقتی کامپوننت فرزند در render یا lifecycle خطا میاندازد، React کل درخت را حذف نمیکند، بلکه کنترل را به نزدیکترین Error Boundary بالاتر در سلسلهمراتب میدهد. Boundary متد getDerivedStateFromError را فراخوانی میکند، state.hasError = true تنظیم میکند و به جای شاخه خراب کامپوننتها fallback UI رندر میکند.
import React, { Component, ErrorInfo, ReactNode } from "react"
interface Props {
children: ReactNode
fallback?: ReactNode
}
interface State {
hasError: boolean
error?: Error
}
class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props)
this.state = { hasError: false }
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error }
}
componentDidCatch(error: Error, info: ErrorInfo) {
console.error("توسط boundary گرفته شد:", error)
Crashlytics.recordException(error)
}
render() {
if (this.state.hasError) {
return this.props.fallback || <FallbackUI />
}
return this.props.children
}
}
getDerivedStateFromError وضعیت را برای رندر fallback UI تنظیم میکند — این یک متد ایستا است که در مرحله رندر قبل از تثبیت تغییرات فراخوانی میشود. componentDidCatch در مرحله تثبیت اجرا میشود و برای عوارض جانبی طراحی شده است: ثبت وقایع، ارسال crash-report به Crashlytics، تحلیل. دو متد مسئولیت را بین مدیریت وضعیت UI و عوارض جانبی تقسیم میکنند.
برای ایجاد Error Boundary باید یک کامپوننت کلاسی با متدهای getDerivedStateFromError و/یا componentDidCatch پیادهسازی کنید. کامپوننتهای تابعی نمیتوانند Error Boundary باشند — React این قابلیت را فقط برای کامپوننتهای کلاسی پشتیبانی میکند، زیرا دسترسی به متدهای چرخه حیات لازم است. کتابخانه react-error-boundary یک پیادهسازی آماده کلاسی با API هوک برای راحتی ارائه میدهد.
// مثال استفاده از Error Boundary در React Native
import { ErrorBoundary } from "react-error-boundary"
const FallbackComponent = ({ error, resetError }: FallbackProps) => (
<View style={styles.container}>
<Text>مشکلی پیش آمد</Text>
<Text>{error.message}</Text>
<Button title="تلاش مجدد" onPress={resetError} />
</View>
)
const App = () => (
<SafeAreaView>
<ErrorBoundary FallbackComponent={<FallbackComponent />}>
<UserProfile userId={"123"} />
</ErrorBoundary>
<BottomNavigation />
</SafeAreaView>
)
سطوح wrapper — Error Boundary را میتوان در سطوح مختلف سلسلهمراتب قرار داد. یک Boundary سراسری در ریشه برنامه در هر خطایی fallback UI نشان میدهد، اما ناوبری همچنان کار میکند. چندین Boundary در سطح صفحه به ایزوله کردن خطاها کمک میکند: اگر یک صفحه خراب شد، بقیه به طور مستقل به کار خود ادامه میدهند. react-error-boundary مکانیزم Reset را از طریق هوک useErrorBoundary ساده میکند و امکان بازنشانی وضعیت بدون بارگذاری مجدد را فراهم میکند. برای پروژههای معمولی، طرح با سه سطح Boundary برای برنامههای React Native بهینه در نظر گرفته میشود.
پس از وقوع خطا، کاربر میتواند دکمه «تلاش مجدد» را فشار دهد که hasError را به false بازنشانی کرده و درخت فرزند را دوباره رندر میکند. مکانیزم Reset برای بازیابی قابلیت کار برنامه بدون بارگذاری مجدد مهم است. در react-error-boundary از callback onReset استفاده میشود که میتواند کش را پاک کند، دادهها را دوباره درخواست کند یا وضعیت بالاتر درخت را بهروزرسانی کند.
Error Boundary خطاهای ناهمگام را نمیگیرد — خطاهای setTimeout، setInterval، Promise، async/await. React نمیتواند خطاهای خارج از چرخه render و lifecycle-hookها را بگیرد، زیرا آنها در زمینههای اجرایی دیگری اجرا میشوند. برای خطاهای ناهمگام نیاز به try-catch جداگانه در handlerها یا handler سراسری رویداد unhandledrejection است.
خطاهای onClick، onChange و سایر event-handlerها توسط Error Boundary گرفته نمیشوند، زیرا خارج از رندر React اجرا میشوند. مدیریت خطا برای event-handlerها باید از طریق try-catch داخل خود handler انجام شود. کتابخانه react-error-boundary هوک useErrorHandler را برای ارسال خطاها از event-handlerها به نزدیکترین Boundary ارائه میدهد.
Error Boundary در سمت سرور در Next.js یا Gatsby کار نمیکند. متدهای getDerivedStateFromError و componentDidCatch در SSR فراخوانی نمیشوند، زیرا متدهای چرخه حیات فقط در مرورگر در دسترس هستند. برای خطاهای سرور نیاز به استراتژی جداگانه است: try-catch در getServerSideProps، صفحات fallback error.js (Next.js 13+) یا middleware سراسری.
در React Native Error Boundary از سقوط در سطح ماژولهای بومی جلوگیری نمیکند. سقوط بومی (segfault، out-of-memory، استثنای بومی) در سطح Objective-C یا Java رخ میدهد و به لایه JavaScript نمیرسد. برای سقوطهای بومی به Crashlytics NDK (Android) یا KSCrash (iOS) نیاز است. Error Boundary فقط از لایه JavaScript برنامه React Native محافظت میکند.
Error Boundary را در مرزهای ماژولهای معنایی قرار دهید: یک Boundary برای هر صفحه، یک Boundary برای ویجت توسعهدهنده شخص ثالث، یک Boundary برای فرم پیچیده. این کار خطاها را ایزوله میکند و به کاربر اجازه میدهد در بقیه بخشهای برنامه به کار ادامه دهد. Boundary ریشه باید همیشه وجود داشته باشد — برای خطاهای بحرانی در کامپوننتهای مشترک ناوبری یا providerها. هر Boundary مسئول قطعه رابط خود است و در صورت وقوع خطا روی کامپوننتهای مجاور تأثیر نمیگذارد.
همیشه خطا را از طریق componentDidCatch به Crashlytics یا Sentry ارسال کنید. زمینه اضافه کنید: نام صفحه، userId، نسخه برنامه، پارامترهای ناوبری. در Sentry breadcrumbs در دسترس هستند — دنباله اقدامات کاربر قبل از خطا. برای تحلیل فراوانی خطاهای غیربحرانی از داشبوردهای Crashlytics با گروهبندی بر اساس issue استفاده کنید.
از fallback «خالی» استفاده نکنید — یک رابط معنادار ایجاد کنید. مجموعه توصیهشده برای React Native: پیام خطا (دوستانه برای کاربر، نه فنی)، دکمه «تلاش مجدد»، لینک پشتیبانی یا چت. از View خالی خودداری کنید — کاربر فکر میکند برنامه کاملاً خراب شده و آن را میبندد. Fallback باید در طراحی کلی برنامه ادغام شود.
هر Error Boundary را با React Testing Library یا React Native Testing Library تست کنید. یک کامپوننت محرک ایجاد کنید که در زمان رندر خطا میاندازد و بررسی کنید که fallback UI نمایش داده میشود. برای تستهای یکپارچهسازی از storybook با حالتهای مختلف Error Boundary استفاده کنید: عادی، خطا، حالت پس از بازنشانی. تست خودکار Boundary تضمین میکند که هنگام تغییر کامپوننت، fallback UI در production به درستی کار میکند. پوشش تست هر Boundary باید یک الزام اجباری code review برای پروژههای React Native باشد.
سوالات متداول
React Error Boundary را فقط از طریق کامپوننتهای کلاسی پیادهسازی میکند، زیرا دسترسی به متدهای چرخه حیات componentDidCatch و getDerivedStateFromError لازم است. کامپوننتهای تابعی چنین متدهایی ندارند. کتابخانه react-error-boundary یک wrapper کلاسی آماده با API هوک برای سهولت استفاده ارائه میدهد.
تأثیر حداقلی است — Error Boundary در هر رندر درخت فرزند یک بررسی وضعیت اضافه میکند. مقایسه state.hasError یک عملیات O(1) با پیچیدگی ثابت است. در نبود خطاها overhead وجود ندارد. فقط هنگام وقوع خطا، Boundary یک رندر اضافی fallback UI انجام میدهد.
خیر، 2–3 سطح کافی است: ریشه Boundary برای کل برنامه، صفحه Boundary برای هر شاخه ناوبری و محلی Boundary برای ویجتهای بحرانی (فرم پرداخت، نقشه، چت). تعداد بیش از حد Boundary معماری را بدون سود قابل توجه پیچیده میکند.
Error Boundary و Suspense مستقل هستند: Suspense بارگذاری (Promise در حال انتظار در React 18+) را میگیرد، Error Boundary خطاهای رندر را میگیرد. میتوان آنها را ترکیب کرد: <ErrorBoundary><Suspense><Component /></Suspense></ErrorBoundary>. Suspense در هنگام بارگذاری اول اجرا میشود، Error Boundary — در خطای کامپوننت بارگذاریشده.
try-catch خطاها را در کد امری همگام میگیرد، اما نمیتواند خطاهای رندر JSX را بگیرد. Error Boundary به طور خاص برای UI اعلامی طراحی شده است: خطاها را در render، lifecycle-hookها و سازندههای کامپوننتهای فرزند میگیرد، که try-catch به دلیل ویژگیهای رندر React نمیتواند انجام دهد.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید