Error Boundary هو مكون React يلتقط أخطاء JavaScript في شجرة المكونات الفرعية ويعرض واجهة بديلة بدلاً من صفحة الانهيار. في سياق React Native، يمنع تعطل التطبيق بالكامل أثناء أخطاء العرض غير الحرجة. وفقًا لوثائق React، 2024، يلتقط error boundary الأخطاء في طرق render، وخطافات دورة الحياة والمنشئات للمكونات الفرعية، مما يسمح للتطبيق بمواصلة العمل. في React Native، هذا مهم بشكل خاص لأن التطبيق المحمول لا يمكن إعادة تحميله باستخدام F5 — يفقد المستخدم جلسته بالكامل.
الخلاصة
Error Boundary هو آلية React للتدهور التدريجي أثناء أخطاء العرض. تم تقديمه في React 16 (2017) كمكون غلاف ينفذ إحدى طريقتين لدورة الحياة: static getDerivedStateFromError أو componentDidCatch. يسمح Error Boundary بعرض رسالة ذات معنى للمستخدم بدلاً من شاشة بيضاء فارغة أو تعطل كامل للتطبيق.
قبل React 16، أي خطأ غير معالج في render كان يؤدي إلى تعطل كامل للتطبيق مع إزالة شجرة DOM بأكملها. في تطبيقات الويب، كان هذا يعني شاشة بيضاء فارغة؛ في React Native، تعطل كامل مع العودة إلى الشاشة الرئيسية. قدم فريق React Error Boundary كمكافئ لكتلة catch لواجهة المستخدم التصريحية، مستعيرًا المفهوم من نهج “let it crash” في لغة Erlang.
في React Native، يعني غياب Error Boundary تعطلًا كاملاً للتطبيق عند أي خطأ في العرض. يفقد المستخدم جلسته الحالية بالكامل دون خيارات استرداد. Error Boundary في React Native مهم بشكل حاسم لأن التطبيقات المحمولة لا يمكن إعادة تحميلها مثل صفحات الويب — جلسة المستخدم تُفقد بشكل لا رجعة فيه، ويضطر المستخدم للبدء من الصفر.
Error Boundary يعمل على مستوى شجرة React. عندما يرمي مكون فرعي خطأ في render أو دورة الحياة، لا يقوم React بإزالة الشجرة بأكملها بل ينقل التحكم إلى أقرب Error Boundary أعلى في التسلسل الهرمي. يستدعي Boundary getDerivedStateFromError، ويضبط state.hasError = true، ويعرض واجهة بديلة بدلاً من فرع المكونات المعطل.
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("Caught by boundary:", error)
Crashlytics.recordException(error)
}
render() {
if (this.state.hasError) {
return this.props.fallback || <FallbackUI />
}
return this.props.children
}
}
getDerivedStateFromError يضبط الحالة لعرض الواجهة البديلة — وهي طريقة ثابتة تُستدعى خلال مرحلة العرض قبل تأكيد التغييرات. componentDidCatch يُنفذ في مرحلة التأكيد وهو مخصص للآثار الجانبية: التسجيل، إرسال تقارير الأعطال إلى Crashlytics، التحليلات. تفصل الطريقتان المسؤولية بين إدارة حالة واجهة المستخدم والآثار الجانبية.
لإنشاء Error Boundary، تحتاج إلى تنفيذ مكون فئة بطرق getDerivedStateFromError و/أو componentDidCatch. المكونات الوظيفية لا يمكن أن تكون Error Boundary — React يدعم هذه الوظيفة فقط للمكونات الفئوية لأن الوصول إلى طرق دورة الحياة مطلوب. توفر مكتبة react-error-boundary تطبيقًا جاهزًا مع واجهة برمجة تطبيقات قائمة على hooks للراحة.
// مثال استخدام 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>
)
مستويات التغليف — يمكن وضع Error Boundary في مستويات مختلفة من التسلسل الهرمي. سيعرض Boundary عام في جذر التطبيق واجهة بديلة عند أي خطأ، لكن التنقل سيظل محفوظًا. تسمح Boundaries متعددة على مستوى الشاشة بعزل الأخطاء: إذا تعطلت شاشة واحدة، تستمر البقية في العمل بشكل مستقل. react-error-boundary يبسط آلية إعادة التعيين من خلال خطاف useErrorBoundary، مما يسمح بإعادة تعيين الحالة دون إعادة تحميل. للمشاريع النموذجية، يعتبر مخطط ثلاثي المستويات من Boundary مثاليًا لتطبيقات React Native.
بعد حدوث خطأ، يمكن للمستخدم النقر على زر “إعادة المحاولة”، الذي يعيد تعيين hasError إلى false ويعيد عرض الشجرة الفرعية. آلية إعادة التعيين مهمة لاستعادة وظائف التطبيق دون إعادة تحميل. في react-error-boundary، يتم استخدام回调 onReset، والذي يمكنه مسح ذاكرة التخزين المؤقت، أو إعادة جلب البيانات، أو تحديث الحالة في مستويات أعلى من الشجرة.
Error Boundary لا يلتقط الأخطاء غير المتزامنة — الأخطاء في setTimeout، setInterval، Promise، async/await. لا يمكن لـ React اعتراض الأخطاء خارج دورة العرض وخطافات دورة الحياة لأنها تُنفذ في سياقات تنفيذ مختلفة. للأخطاء غير المتزامنة، هناك حاجة إلى try-catch منفصل في المعالجات أو معالج عام لحدث unhandledrejection.
الأخطاء في onClick، onChange ومعالجات الأحداث الأخرى لا يتم التقاطها بواسطة Error Boundary لأنها تُنفذ خارج عرض React. معالجة الأخطاء لمعالجات الأحداث يجب أن تكون داخل المعالج نفسه باستخدام try-catch. توفر مكتبة react-error-boundary خطاف useErrorHandler لرمي الأخطاء من معالجات الأحداث إلى أقرب Boundary.
Error Boundary لا يعمل على جانب الخادم في Next.js أو Gatsby. لا يتم استدعاء طريقتي getDerivedStateFromError و componentDidCatch أثناء SSR لأن طرق دورة الحياة متاحة فقط في المتصفح. لأخطاء الخادم، هناك حاجة إلى استراتيجية منفصلة: try-catch في getServerSideProps، صفحات احتياطية error.js (Next.js 13+)، أو middleware عام.
في React Native، لا يمنع Error Boundary الأعطال على مستوى الوحدات الأصلية. العطل الأصلي (segfault، نفاد الذاكرة، استثناء أصلي) يحدث على مستوى Objective-C أو Java ولا يصل إلى طبقة JavaScript. للأعطال الأصلية، هناك حاجة إلى Crashlytics NDK (Android) أو KSCrash (iOS). Error Boundary يحمي فقط طبقة JavaScript لتطبيق React Native.
ضع Error Boundary على حدود الوحدات المنطقية: Boundary واحد لكل شاشة، واحد لكل أداة طرف ثالث، واحد لكل نموذج معقد. هذا يعزل الأخطاء ويسمح للمستخدم بمواصلة العمل في أجزاء أخرى من التطبيق. يجب أن يكون هناك Boundary جذر دائمًا — للأخطاء الحرجة في مكونات التنقل المشتركة أو المزودين. كل Boundary مسؤول عن جزء الواجهة الخاص به ولا يؤثر على المكونات المجاورة عند حدوث خطأ.
قم دائمًا بتمرير الخطأ إلى Crashlytics أو Sentry من خلال componentDidCatch. أضف سياقًا: اسم الشاشة، userId، إصدار التطبيق، معلمات التنقل. في Sentry، تتوفر breadcrumbs — سلسلة من إجراءات المستخدم التي أدت إلى الخطأ. لتحليل تكرار الأخطاء غير المميتة، استخدم لوحات Crashlytics مع التجميع حسب المشكلة.
لا تستخدم fallback بسيط — أنشئ واجهة ذات معنى. المجموعة الموصى بها لـ React Native: رسالة خطأ (سهلة للمستخدم، غير تقنية)، زر “إعادة المحاولة”، رابط للدعم أو الدردشة. تجنب العرض الفارغ — سيعتقد المستخدم أن التطبيق تعطل بالكامل وسيغلقه. يجب أن يكون fallback مدمجًا في التصميم العام للتطبيق.
اختبر كل Error Boundary باستخدام React Testing Library أو React Native Testing Library. أنشئ مكون مشغل يرمي خطأ عند العرض وتحقق من ظهور الواجهة البديلة. لاختبارات التكامل، استخدم storybook بحالات مختلفة لـ Error Boundary: عادي، خطأ، حالة ما بعد إعادة التعيين. يضمن الاختبار الآلي لـ Boundary أنه عند تغيير المكون، تستمر الواجهة البديلة في العمل بشكل صحيح في الإنتاج. يجب أن يكون تغطية الاختبار لكل Boundary مطلبًا إلزاميًا لمراجعة الكود لمشاريع React Native.
الأسئلة الشائعة
يقوم React بتنفيذ Error Boundary فقط من خلال المكونات الفئوية لأن الوصول إلى طرق دورة الحياة componentDidCatch و getDerivedStateFromError مطلوب. المكونات الوظيفية لا تحتوي على مثل هذه الطرق. توفر مكتبة react-error-boundary غلافًا فئويًا جاهزًا مع واجهة برمجة تطبيقات قائمة على hooks لسهولة الاستخدام.
التأثير ضئيل — Error Boundary يضيف فحص حالة عند كل عرض للشجرة الفرعية. مقارنة state.hasError هي عملية O(1) بتعقيد ثابت. عند عدم وجود أخطاء، لا يوجد حمل إضافي. فقط عند حدوث خطأ، يقوم Boundary بعرض إضافي للواجهة البديلة.
لا، 2–3 مستويات كافية: Boundary جذر للتطبيق بالكامل، Boundary شاشة لكل فرع تنقل، و Boundary محلي للأدوات الحرجة (نموذج الدفع، الخريطة، الدردشة). الاستخدام المفرط لـ Boundaries يعقد البنية دون فائدة كبيرة.
Error Boundary و Suspense مستقلان: Suspense يلتقط التحميل (Promise معلق في React 18+)، Error Boundary يلتقط أخطاء العرض. يمكن دمجهما: <ErrorBoundary><Suspense><Component /></Suspense></ErrorBoundary>. Suspense يعمل أولاً أثناء التحميل، Error Boundary يعمل عند خطأ المكون المحمل.
try-catch يلتقط الأخطاء في الكود الأمري المتزامن ولكنه لا يستطيع اعتراض أخطاء عرض JSX. Error Boundary مصمم خصيصًا لواجهة المستخدم التصريحية: يعترض الأخطاء في render، وخطافات دورة الحياة، والمنشئات للمكونات الفرعية، وهو ما لا يمكن لـ try-catch فعله بسبب خصوصيات عرض React.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا