اشکال‌زدایی (debug): افزونه‌ی react developer tools و قابلیت Error Boundary

Debugging: Add Developer Tools Plugin and Error Boundary Feature

اشکال‌زدایی (debug): افزونه ی react developer tools و قابلیت Error Boundary

افزونه react developer tools برای دیباگ کردن در ری اکت

در جلسه قبل یاد گرفتیم که با استفاده از پیام های خطای نمایش داده شده در console و خود مرورگر می توانیم از error message ها استفاده کنیم و مشکل را شناسایی کنیم. همچنین هنگام برخورد با خطاهای منطقی می توانیم از developer tools خود مرورگر برای حل مشکل استفاده کنیم. اما کار با developer tools مرورگر مختص به react نیست و به همین خاطر ویژگی های زیادی ندارد و ما باید برای پیدا کردن خطاهایمان وقت و تلاش زیادی را خرج کنیم.

خوشبختانه یک extension برای مرورگر کروم وجود دارد که به آن react developer tools می گوییم. این extension به شما اجازه می دهد روند خطایابی را بسیار سریع تر و راحت تر انجام دهید. شما می توانید در هر زمان با یک جستجوی ساده در گوگل آن را پیدا کنید. زمانی که به webstore کروم (صفحه افزونه ها برای کروم) رسیدید، گزینه Add to chrome را بزنید (بهتر است مرورگر خود را به آخرین نسخه بروزرسانی کنید). پس از نصب یک بار مرورگرتان را ری استارت کنید (ببندید و دوباره باز کنید).

حالا در صفحه developer tools قسمت components و profiler را مشاهده خواهید کرد. برای اطلاعات بیشتر به این صفحه مراجعه کنید. این ابزار به شما اجازه می دهد که کامپوننت های مختلف را مشاهده کنید و اطلاعات کاملی به شما می دهد:

دیباگ کردن در ری اکت
نمایی از react developer tools

استفاده از این ابزار مانند سربرگ elements در کروم است و نیازی به آموزش خاصی ندارد.

نمایش خطا به کاربر با قابلیت Error Boundary

ما می دانیم که برخی اوقات برنامه هایی که می نویسیم ممکن است با خطا مواجه شوند. در چنین حالاتی بهتر است پیام خطایی را به کاربران نمایش دهیم تا بدانند چه اتفاقی افتاده است. به طور مثال فرض کنید هنگامی که می خواهیم کلاس person را نمایش دهیم (فایل Person.js) ممکن است به خطا برخورد کنیم (یک احتمال ساده و البته ممکن!). بنابراین یک سناریوی ساختگی برای خودمان می سازیم تا به شما نشان بدهم چطور باید این کار را انجام بدهید.

تا این لحظه کدهای فایل Person.js به این شکل است:

import React from 'react';
import classes from './Person.css';

const person = (props) => {
    return (
        <div className={classes.Person}>
            <p onClick={props.click}>I'm {props.name} and I am {props.age} years old!</p>
            <p>{props.children}</p>
            <input type="text" onChange={props.changed} value={props.name} />
        </div>
    )
};

export default person;

از آنجایی که ما به خطا برخورد نمی کنیم، یک کد ساده می نویسیم تا یک عدد تصادفی به ما بدهد. سپس می گوییم اگر عدد تصادفی بیشتر از فلان مقدار بود فرض می کنیم که خطا اتفاق افتاده است. این کار را فقط برای آموزش انجام می دهم و استفاده دیگری ندارد:

const person = (props) => {
    const rnd = Math.random();
    if (rnd > 0.7) {
        throw new Error('something went wrong');
    }
    return (
        <div className={classes.Person}>
            <p onClick={props.click}>I'm {props.name} and I am {props.age} years old!</p>
            <p>{props.children}</p>
            <input type="text" onChange={props.changed} value={props.name} />
        </div>
    )
};

تابع random از شیء Math یک عدد تصادفی را برمی گرداند. ما گفته ایم اگر این عدد بیشتر از 0.7 بود یک خطای جدید نمایش بده و بگو «something went wrong»

اگر به مرورگر بروید و چند بار روی کلید Show persons کلیک کنید باید بالاخره به یک خطا برخورد کنید. در برنامه های دنیای واقعی احتمال دارد که به خطاهای زیادی برخورد کنیم چرا که باید با انواع وب سرویس ها و پایگاه های داده و... در تماس باشیم. بنابراین اگر بتوانیم این خطای پرتاب شده (throw) را دریافت کنیم و به کاربر نمایش دهیم بسیار خوب می شود!

در نسخه 16 کتابخانه react یک قابلیت جدید به نام Error Boundary معرفی شده است که این کار را انجام می دهد. در پوشه اصلی پروژه (src) یک پوشه دیگر به نام ErrorBoundary و درون آن یک فایل به نام ErrorBoundary.js ایجاد می کنیم. شما می توانید هر نام دیگری که خواستید انتخاب کنید. برای ایجاد این کامپوننت باید از کامپوننت های کلاس-محور استفاده کنیم.

import React, { Component } from 'react';

class ErrorBoundary extends Component {
    render() {
        return <h1>Something went wrong</h1>;
    }
}

یک کامپوننت به نام ErrorBoundary ایجاد کرده ایم و همانطور که می دانید کامپوننت های کلاس-محور باید Component را Extend کنند. فعلا این کامپوننت یک تگ h1 را نمایش می دهد و می گوید something went wrong اما ما می خواهیم چنین چیزی فقط زمانی نمایش داده شود که خطایی اتفاق افتاده باشد. بنابراین:

class ErrorBoundary extends Component {
    state = {
        hasError: false,
        errorMessage: ''
    }
    render() {
        return <h1>Something went wrong</h1>;
    }
}

استفاده از state یکی از دلایلی است که باید از کامپوننت کلاس-محور استفاده می کردیم.

React یک متد از پیش تعریف شده به نام componentDidCatch دارد که خطا (error) را به همراه اطلاعات اضافی دیگر (info) می گیرد (react خودش این اطلاعات را به این دو متغیر پاس خواهد داد و شما نیازی نیست چیزی به آن بدهید):

    componentDidCatch = (error, info) => {
        
    }

اگر ما کامپوننتی (مثلا person) را درون کامپوننت ErrorBoundary قرار دهیم و آن کامپوننت (person) خطایی throw کند، متد componentDidCatch اجرا خواهد شد. بگذارید به صورت عملی نشانتان بدهم:

import React, { Component } from 'react';

class ErrorBoundary extends Component {
    state = {
        hasError: false,
        errorMessage: ''
    }

    componentDidCatch = (error, info) => {
        this.setState({
            hasError: true,
            errorMessage: error
        });
    }

    render() {
        if (this.state.hasError) {
            return <h1>{this.state.errorMessage}</h1>;
        } else {
            return this.props.children;
        }
    }
}

export default ErrorBoundary;

زمانی که کامپوننتی خطا داشته باشد متد componentDidCatch اجرا شده و وضعیت state را تغییر می دهد (آرگومان error توسط خود react ارسال می شود). سپس گفته ایم اگر در state وضعیت خطا (hasError) صحیح یا true باشد باید عبارت something went wrong نمایش داده شود در غیر این صورت هر چیزی که درون کامپوننت ErrorBoundary باشد.

وارد فایل App.js می شویم و ابتدا برای استفاده از آن باید آن را import کنیم:

import ErrorBoundary from './ErrorBoundary/ErrorBoundary';

حالا به قسمت JSX رفته و کامپوننت Person را درون ErrorBoundary قرار می دهیم:

if (this.state.showPersons) {
      persons = (
        <div>
          {this.state.persons.map((person, index) => {
            return <ErrorBoundary ><Person
              click={() => this.deletePersonHandler(index)}
              name={person.name}
              age={person.age}
              key={person.id}
              changed={(event) => this.nameChangedHandler(event, person.id)}
            /></ErrorBoundary>
          })}
        </div>
      );

      btnClass = classes.Red;
}

به کامپوننت هایی مانند ErrorBoundary کامپوننت های Higher order (کامپوننت هایی با اولویت بالاتر) می گوییم (دیگر کامپوننت ها را درون خودشان دارند). کار ErrorBoundary دریافت هر خطایی است که ممکن است توسط Person پرتاب (throw) شود.

در متد map (که در همین قسمت استفاده شده است) مقدار key باید همیشه روی عنصر خارجی باشد بنابراین باید key را از person برداشته و روی ErrorBoundary قرار دهیم. بنابراین:

    if (this.state.showPersons) {
      persons = (
        <div>
          {this.state.persons.map((person, index) => {
            return <ErrorBoundary key={person.id}><Person
              click={() => this.deletePersonHandler(index)}
              name={person.name}
              age={person.age}
              changed={(event) => this.nameChangedHandler(event, person.id)}
            /></ErrorBoundary>
          })}
        </div>
      );

متاسفانه ما در حالت development build هستیم (در حال توسعه برنامه) به همین دلیل react پیام خطای ما را در مرورگر نمایش نمی دهد و هنوز هم از خطای خود استفاده میکند و فقط زمانی که به production build برویم (نسخه قابل استفاده برای همه) می توانیم پیام خطای خود را ببینیم. بنابراین فعلا در مرورگر چیزی نمی بینید اما مهم این است که نحوه انجام کار به همین صورت خواهد بود.

نکته: فقط و فقط قسمت هایی از کد را درون Error Boundary قرار دهید که احتمال می دهید با خطا همراه شود؛ یعنی کنترل آن دست شما نباشد (مانند ارتباط با وب سرویس یا پایگاه داده و...). بدون حساب و کتاب از Error Boundary ها استفاده نکنید چرا که برنامه شما را کند می کنند.

دانلود کدهای این جلسه

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری دوره جامع آموزش ری اکت توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.