یاد بگیرید چگونه خطاها را در React Error Boundaries بهطور موثر دستهبندی و مدیریت کنید و پایداری و تجربه کاربری را بهبود ببخشید.
دستهبندی خطاهای Boundary خطای React: راهنمای جامع
مدیریت خطا یک جنبه حیاتی از ساخت برنامههای React قوی و قابل نگهداری است. در حالی که React Error Boundaries مکانیزمی را برای مدیریت ظریف خطاها که در طول رندر رخ میدهند، ارائه میدهد، درک نحوه دستهبندی و پاسخ به انواع مختلف خطا برای ایجاد یک برنامه واقعاً انعطافپذیر بسیار مهم است. این راهنما رویکردهای مختلفی را برای دستهبندی خطا در Error Boundaries بررسی میکند، مثالهای عملی و بینشهای قابل اجرا را برای بهبود استراتژی مدیریت خطای شما ارائه میدهد.
Error Boundaries های React چیستند؟
Error Boundaries ها که در React 16 معرفی شدند، کامپوننتهای React هستند که خطاهای جاوا اسکریپت را در هر جایی از درخت کامپوننت فرزند خود به دام میاندازند، آن خطاها را ثبت میکنند و به جای از کار انداختن کل درخت کامپوننت، یک رابط کاربری جایگزین را نمایش میدهند. آنها عملکردی مشابه یک بلوک try...catch دارند، اما برای کامپوننتها.
ویژگیهای کلیدی Error Boundaries:
- مدیریت خطا در سطح کامپوننت: خطاها را در زیردرختهای کامپوننت خاص ایزوله کنید.
- تخریب ظریف: از از کار افتادن کل برنامه به دلیل یک خطای کامپوننت واحد جلوگیری کنید.
- رابط کاربری جایگزین کنترل شده: هنگام بروز خطا، یک پیام کاربرپسند یا محتوای جایگزین را نمایش دهید.
- ثبت خطا: با ثبت اطلاعات خطا، ردیابی و اشکال زدایی خطاها را تسهیل کنید.
چرا خطاها را در Error Boundaries دستهبندی کنیم؟
به سادگی گرفتن خطا کافی نیست. مدیریت موثر خطا نیازمند درک این است که چه چیزی اشتباه شده و پاسخ متناسب با آن است. دستهبندی خطاها در Error Boundaries مزایای متعددی را ارائه میدهد:
- مدیریت خطای هدفمند: انواع مختلف خطا ممکن است به پاسخهای متفاوتی نیاز داشته باشند. به عنوان مثال، خطای شبکه ممکن است یک مکانیسم تکرار را تضمین کند، در حالی که خطای اعتبارسنجی داده ممکن است نیازمند اصلاح ورودی کاربر باشد.
- تجربه کاربری بهبود یافته: پیامهای خطای آموزندهتری را بر اساس نوع خطا نمایش دهید. یک پیام عمومی «مشکلی پیش آمد» کمتر مفیدتر از یک پیام خاص که نشاندهنده مشکل شبکه یا ورودی نامعتبر است، است.
- اشکال زدایی پیشرفته: دستهبندی خطاها زمینه با ارزشی را برای اشکال زدایی و شناسایی علت اصلی مشکلات فراهم میکند.
- نظارت فعالانه: فراوانی انواع مختلف خطا را ردیابی کنید تا مشکلات مکرر را شناسایی کرده و رفعها را اولویتبندی کنید.
- رابط کاربری جایگزین استراتژیک: رابطهای کاربری جایگزین متفاوتی را بسته به خطا نمایش دهید و اطلاعات یا اقدامات مرتبطتری را به کاربر ارائه دهید.
رویکردها برای دستهبندی خطا
از تکنیکهای مختلفی میتوان برای دستهبندی خطاها در React Error Boundaries استفاده کرد:
1. استفاده از instanceof
عملگر instanceof بررسی میکند که آیا یک شیء نمونهای از یک کلاس خاص است یا خیر. این برای دستهبندی خطاها بر اساس انواع خطای داخلی یا سفارشی آنها مفید است.
مثال:
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;
}
}
توضیحات:
- کلاسهای سفارشی
NetworkErrorوValidationErrorتعریف شدهاند که کلاس داخلیErrorرا گسترش میدهند. - در متد
renderکامپوننتMyErrorBoundary، از عملگرinstanceofبرای بررسی نوع خطای گرفته شده استفاده میشود. - بر اساس نوع خطا، یک پیام خطای خاص در رابط کاربری جایگزین نمایش داده میشود.
2. استفاده از کدهای خطا یا ویژگیها
رویکرد دیگر این است که کدهای خطا یا ویژگیها را در خود شیء خطا قرار دهید. این امکان دستهبندی ریزدانه تر را بر اساس سناریوهای خطای خاص فراهم میکند.
مثال:
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;
}
}
توضیحات:
- تابع
fetchDataیک ویژگیcodeرا به شیء خطا اضافه میکند که نشان دهنده کد وضعیت HTTP است. - کامپوننت
MyErrorBoundaryویژگیcodeرا بررسی میکند تا سناریوی خطای خاص را تعیین کند. - پیامهای خطای مختلف بر اساس کد خطا نمایش داده میشوند.
3. استفاده از یک نقشه خطای متمرکز
برای برنامههای پیچیده، حفظ یک نقشه خطای متمرکز میتواند سازماندهی و قابلیت نگهداری کد را بهبود بخشد. این شامل ایجاد یک دیکشنری یا شیء است که انواع خطا یا کدها را به پیامهای خطای خاص و منطق رسیدگی ترسیم میکند.
مثال:
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>;
}
توضیحات:
- شیء
errorMapاطلاعات خطا، از جمله پیامها و پرچمهای تکرار را بر اساس انواع یا کدهای خطا ذخیره میکند. - تابع
handleCustomErrorجزئیات خطا را ازerrorMapبر اساس پیام خطا بازیابی میکند و در صورت یافت نشدن کد خاص، پیشفرضها را برمیگرداند. - کامپوننت
MyErrorBoundaryازhandleCustomErrorبرای دریافت پیام خطای مناسب ازerrorMapاستفاده میکند.
بهترین روشها برای دستهبندی خطا
- تعریف انواع خطای واضح: مجموعهای ثابت از انواع یا کدهای خطا را برای برنامه خود ایجاد کنید.
- ارائه اطلاعات زمینهای: جزئیات مرتبط را در اشیاء خطا قرار دهید تا اشکال زدایی تسهیل شود.
- متمرکز کردن منطق مدیریت خطا: از یک نقشه خطای متمرکز یا توابع کاربردی برای مدیریت سازگار مدیریت خطا استفاده کنید.
- ثبت موثر خطاها: با سرویسهای گزارشدهی خطا ادغام شوید تا خطاها را در تولید ردیابی و تجزیه و تحلیل کنید. خدمات محبوب شامل Sentry، Rollbar و Bugsnag است.
- تست مدیریت خطا: برای تأیید اینکه Error Boundaries های شما به درستی انواع مختلف خطا را مدیریت میکنند، آزمونهای واحد بنویسید.
- تجربه کاربری را در نظر بگیرید: پیامهای خطای آموزنده و کاربرپسند را نمایش دهید که کاربران را به سمت راهحل هدایت میکند. از اصطلاحات فنی خودداری کنید.
- نظارت بر نرخ خطا: فراوانی انواع مختلف خطا را ردیابی کنید تا مشکلات مکرر را شناسایی کرده و رفع را اولویتبندی کنید.
- بینالمللیسازی (i18n): هنگام ارائه پیامهای خطا به کاربر، اطمینان حاصل کنید که پیامهای شما بهدرستی بینالمللی شدهاند تا از زبانها و فرهنگهای مختلف پشتیبانی کنند. از کتابخانههایی مانند
i18nextیا React's Context API برای مدیریت ترجمهها استفاده کنید. - دسترسی (a11y): اطمینان حاصل کنید که پیامهای خطای شما برای کاربران دارای معلولیت قابل دسترسی هستند. از ویژگیهای ARIA برای ارائه زمینه اضافی به صفحهخوانها استفاده کنید.
- امنیت: در مورد اطلاعاتی که در پیامهای خطا نمایش میدهید، به ویژه در محیطهای تولید، مراقب باشید. از افشای اطلاعات حساس که میتواند توسط مهاجمان مورد سوء استفاده قرار گیرد، خودداری کنید. به عنوان مثال، ردیابی پشته خام را به کاربران نهایی نشان ندهید.
سناریوی مثال: رسیدگی به خطاهای API در یک برنامه تجارت الکترونیک
یک برنامه تجارت الکترونیک را در نظر بگیرید که اطلاعات محصول را از یک API بازیابی میکند. سناریوهای خطای بالقوه عبارتند از:
- خطاهای شبکه: سرور API در دسترس نیست یا اتصال اینترنت کاربر قطع شده است.
- خطاهای احراز هویت: توکن احراز هویت کاربر نامعتبر یا منقضی شده است.
- خطاهای یافت نشدن منبع: محصول درخواستی وجود ندارد.
- خطاهای سرور: سرور API با یک خطای داخلی مواجه میشود.
با استفاده از Error Boundaries و دستهبندی خطا، برنامه میتواند این سناریوها را به درستی مدیریت کند:
// 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;
}
}
توضیحات:
- تابع
fetchProductکد وضعیت پاسخ API را بررسی میکند و انواع خطای خاص را بر اساس وضعیت پرتاب میکند. - کامپوننت
ProductErrorBoundaryاین خطاها را میگیرد و پیامهای خطای مناسب را نمایش میدهد. - برای خطاهای شبکه و خطاهای سرور، یک دکمه «تکرار» نمایش داده میشود که به کاربر اجازه میدهد تا درخواست را دوباره امتحان کند.
- برای خطاهای احراز هویت، ممکن است کاربر به صفحه ورود هدایت شود.
- برای خطاهای یافت نشدن منبع، پیامی مبنی بر عدم وجود محصول نمایش داده میشود.
نتیجهگیری
دستهبندی خطاها در React Error Boundaries برای ساخت برنامههای انعطافپذیر و کاربرپسند ضروری است. با استفاده از تکنیکهایی مانند بررسیهای instanceof، کدهای خطا و نقشهبرداری خطای متمرکز، میتوانید به طور موثر سناریوهای مختلف خطا را مدیریت کرده و تجربه کاربری بهتری ارائه دهید. به یاد داشته باشید که بهترین شیوهها را برای مدیریت خطا، ثبت و آزمایش دنبال کنید تا اطمینان حاصل کنید که برنامه شما به درستی شرایط غیرمنتظره را مدیریت میکند.
با پیادهسازی این استراتژیها، میتوانید پایداری و قابلیت نگهداری برنامههای React خود را به میزان قابل توجهی بهبود بخشید و بدون توجه به موقعیت مکانی یا پیشینه، تجربه روانتر و مطمئنتری را برای کاربران خود فراهم کنید.
منابع بیشتر: