React دائماً کامپوننت‌ها را re-render می‌کند. بنابراین اگر از اتفاقاتی که در پس‌زمینه می‌افتد با خبر باشیم می‌توانیم برنامه React خود را طوری تنظیم کنیم که سرعت بسیار بالایی داشته باشد. در این مقاله قصد داریم تا درمورد تکنیک‌های پیشرفته‌ای که برای بهینه‌ سازی عملکرد در React در جهت افزایش سرعت برنامه‌های React وجود دارد، صحبت کنیم.

استفاده از ()React.Memo

React.memo یک کامپوننت‌ higher-order است و عملکرد کامپوننت‌های فانکشنال را در React بهینه می‌کند. همچنین نتیجه رندر یک کامپوننت را ذخیره می‌کند و تنها در صورتی که propهای آن تغییر کنند، کامپوننت را دوباره رندر می‌کند.

در ادامه مثالی از نحوه استفاده از React.memoرا بررسی می‌کنیم:

export function MyComponent({ prop1, prop2 }) {
  return (
    <div>
      <div>{prop1}</div>
      <div>{prop2}</div>
    </div>
  )
}
export const MemoizedComponent = React.memo(MyComponent)

در این مثال، MyComponentیک کامپوننت فانکشنال است که دو prop را می‌پذیرد: prop1 و prop2. با قرار دادن آن بین پرانتزهای کامپوننتReact.memo، React فقط در صورتی که هر یک از propهای آن تغییر کند، کامپوننت را دوباره رندر می‌کند.

استفاده از React.memo برای موارد زیر مفید است:

  1. فانکشنال کامپوننت‌هایی که به تعداد بالا رندر می‌شوند
  2. کامپوننت‌هایی که رندر آن‌ها منابع زیادی را نیاز دارد
  3. کامپوننت‌هایی که propهایی را دریافت می‌کنند که مرتباً دچار تغییر نمی‌شوند.

باید این موضوع را به خاطر داشته باشیم که React.memo فقط یک مقایسه سطحی از propهای خود را انجام می‌دهد. اگر کامپوننت ما آبجکت و یا آرایه‌های پیچیده را به عنوان props دریافت می‌کند، ممکن است نیاز به ایجاد یک تابع مقایسه سفارشی داشته باشیم.

Lazy Loading

ویژگی Lazy loading  در React این امکان را به ما می‌دهد که کامپوننت‌ها را بر اساس درخواست لود کنیم. این ویژگی بسیار کارآمدتر از لود همه چیز به طور هم‌زمان و در هنگام شروع برنامه است. از تابع React.lazy()برای ایجاد یک کامپوننت جدید استفاده می‌کنیم که می‌تواند به صورت lazily لود شود. این تابع یک import پویا می‌گیرد، که یک ویژگی جاوااسکریپت است و لود ماژول‌ها را در صورت درخواست امکان‌پذیر می‌کند.

در ادامه مثالی از نحوه استفاده از Lazy loading را باهم بررسی می‌کنیم:

const MyLazyComponent = React.lazy(() => import('./MyComponent'))

MyComponent کامپوننتی است که می‌خواهیم آن را به صورت Lazy لود کنیم. در صورت نیاز، تابع import()ماژول حاوی MyComponentرا لود می‌کند. برای استفاده از MyLazyComponent، آن را در یک کامپوننت لود شده قرار می‌دهیم:

function MyApp() {
  return (
    <div>
      <h1>Welcome to my app!</h1>
      <React.Suspense fallback={<h1>Loading...</h1>}>
        <MyLazyComponent/>
      </React.Suspense>
    </h1>
  );
}

همینطور در این مثال، MyAppیک کامپوننت لود شده است. هنگامی که MyAppرندر می‌شود، React.Suspenseبرای نمایش یک رابط کاربری بازگشتی، مانند نشانگر لود مورد استفاده قرار می‌گیرد. هنگامی که MyLazyComponentلود شد، جایگزین رابط کاربری بازگشتی می‌شود.

Lazy loading برای برنامه‌های بزرگ با کامپوننت‌های متعدد مفید است و می‌تواند به کاهش زمان لود اولیه و بهبود عملکرد کلی کمک کند.

useCallback

هوک useCallbackدر  React توابع را به خاطر می‌سپارد (ذخیره می‌کند) تا عملکرد کامپوننت‌های فانکشنال را بهینه کند. هنگامی که یک تابع داخل useCallbackقرار می‌گیرد، تنها زمانی re-render می‌شود که dependencyهای آن تغییر پیدا کند.

در ادامه مثالی از نحوه استفاده از useCallbackرا بررسی می‌کنیم:

function MyComponent() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return (
    <div>
      <p>Count: {count}</p>
      <button> onClick={handleClick}>Increment/button>
    </div>
  );
}

در این مثال، متغیر count stateتعداد دفعاتی که روی دکمه کلیک شده است را در خود نگه می‌دارد. همچنین یک تابع handleClickداریم که با کلیک روی دکمه، متغیر state شمارش را افزایش می‌دهد.

ما از useCallbackبرای به خاطر سپردن تابع handleClickاستفاده کرده و [count]را به عنوان آرایه dependency آن مشخص می‌کنیم. این بدان معنی است که این تابع تنها در صورت تغییر تعداد دوباره ایجاد می‌شود، نه در هر بار re-render کامپوننت.

استفاده از useCallbackبه ویژه در سناریوهایی می‌تواند مفید باشد که در آن یک تابع به عنوان یک prop به کامپوننت child منتقل می‌شود. با به خاطر سپردن تابع با استفاده از useCallback، می‌توانیم از re-render شدن غیرضروری کامپوننت‌های child که به آن تابع وابسته هستند جلوگیری کنیم.

باید به این نکته توجه داشته باشیم که از هوک useCallbackفقط در مواقع ضروری استفاده کنیم، زیرا می‌تواند پیچیدگی‌هایی را به کد ما اضافه کند. بهتر است از این هوک هنگام انتقال توابع به عنوان prop به کامپوننت‌های child و یا برای توابعی که به منابع زیادی نیاز دارند، استفاده کنیم.

بهینه‌ سازی عملکرد لیست با استفاده از keyها

توسعه‌دهندگان برای بهینه‌ سازی عملکرد در React، از پراپ key برای شناسایی هر آیتم در لیستی از کامپوننت‌ها استفاده می‌کنند. هنگامی که لیستی از کامپوننت‌ها render می‌شود، استفاده از یک key می‌تواند با کمک به React در شناسایی موارد تغییر یافته، عملکرد را بهبود ببخشد.

در ادامه سه نکته برای استفاده موثر از پراپ key را داریم:

  1. بهتر است از یک شناسه منحصربه‌فرد برای پراپ key استفاده کنیم. به جای استفاده از یک ایندکس به عنوان کلید، که می‌تواند در هنگام افزودن یا حذف موارد از لیست، مشکلاتی ایجاد کند باید برای هر موردی که در لیست وجود دارد از یک شناسه منحصربه‌فرد استفاده شود.
  2. از یک شناسه پایدار برای پراپ key استفاده کنیم. در این حالت حتی اگر ترتیب لیست تغییر کند، باید از همان شناسه برای یک مورد خاص استفاده شود. این کار به React کمک می‌کند تا از رندر مجدد غیرضروری جلوگیری کند.
  3. بهتر است پراپ key را به بیرونی‌ترین المنت در دستور بازگشتی یک کامپوننت اعمال کنیم. اعمال کلید بر روی یک المنت داخلی ممکن است باعث بروز یک رفتار غیرمنتظره شود زیرا React از پراپ key برای شناسایی هر کامپوننت استفاده می‌کند.

در ادامه مثالی از نحوه استفاده از key هنگام رندر کردن لیستی از کامپوننت‌ها را باهم بررسی می‌کنیم:

function MyList(props) {
  const items = props.items.map(item => (
     <MyListItem key={item.id} item={item} />
  ));
  return <ul>{items}</ul>;
}

MyListکامپوننتی است که فهرستی از کامپوننت‌های MyListItemرا رندر می‌کند. پراپ key روی item.idتنظیم شده است که یک شناسه منحصربه‌فرد برای هر آیتم در لیست است.

استفاده از key می‌تواند با به حداقل رساندن رندر مجدد غیرضروری کامپوننت‌ها در یک لیست، به بهبود عملکرد در React کمک کند. React با استفاده از یک کلید منحصربه‌فرد و پایدار برای هر آیتم، می‌تواند به راحتی تشخیص دهد که کدام یک از آیتم‌ها تغییر کرده‍اند و باید به روز رسانی شوند.

جمع‌بندی

تکنیک‌های زیادی برای بهینه‌ سازی عملکرد در React وجود دارد اما ما در این مقاله چهار مورد از آن‌ها را مورد بررسی قرار دادیم که عبارتند از: