فارسی

راهنمای جامع برای بهینه‌سازی عملکرد اپلیکیشن‌های React با استفاده از useMemo، useCallback و React.memo. یاد بگیرید چگونه از رندرهای مجدد غیرضروری جلوگیری کرده و تجربه کاربری را بهبود ببخشید.

بهینه‌سازی عملکرد React: تسلط بر useMemo، useCallback و React.memo

React، یک کتابخانه محبوب جاوا اسکریپت برای ساخت رابط‌های کاربری، به خاطر معماری مبتنی بر کامپوننت و سبک اعلانی خود شناخته شده است. با این حال، با افزایش پیچیدگی اپلیکیشن‌ها، عملکرد می‌تواند به یک نگرانی تبدیل شود. رندرهای مجدد غیرضروری کامپوننت‌ها می‌تواند منجر به عملکرد کند و تجربه کاربری ضعیف شود. خوشبختانه، React چندین ابزار برای بهینه‌سازی عملکرد فراهم می‌کند، از جمله useMemo، useCallback و React.memo. این راهنما به بررسی عمیق این تکنیک‌ها می‌پردازد و مثال‌های عملی و بینش‌های کاربردی برای کمک به شما در ساخت اپلیکیشن‌های React با کارایی بالا ارائه می‌دهد.

درک رندرهای مجدد در React

قبل از پرداختن به تکنیک‌های بهینه‌سازی، درک اینکه چرا رندرهای مجدد در React اتفاق می‌افتند، بسیار مهم است. هنگامی که state یا props یک کامپوننت تغییر می‌کند، React یک رندر مجدد از آن کامپوننت و به طور بالقوه، کامپوننت‌های فرزند آن را آغاز می‌کند. React از یک DOM مجازی برای به‌روزرسانی کارآمد DOM واقعی استفاده می‌کند، اما رندرهای مجدد بیش از حد همچنان می‌توانند بر عملکرد تأثیر بگذارند، به خصوص در اپلیکیشن‌های پیچیده. یک پلتفرم تجارت الکترونیک جهانی را تصور کنید که در آن قیمت محصولات به طور مکرر به‌روز می‌شود. بدون بهینه‌سازی، حتی یک تغییر کوچک در قیمت ممکن است باعث رندرهای مجدد در کل لیست محصولات شود و بر مرور کاربران تأثیر بگذارد.

چرا کامپوننت‌ها دوباره رندر می‌شوند

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

معرفی useMemo: مموایز کردن محاسبات سنگین

useMemo یک هوک React است که نتیجه یک محاسبه را مموایز (memoize) می‌کند. مموایزیشن یک تکنیک بهینه‌سازی است که نتایج فراخوانی‌های توابع سنگین را ذخیره می‌کند و در صورت تکرار ورودی‌های مشابه، از آن نتایج ذخیره شده مجدداً استفاده می‌کند. این کار از اجرای غیرضروری تابع جلوگیری می‌کند.

چه زمانی از useMemo استفاده کنیم

useMemo چگونه کار می‌کند

useMemo دو آرگومان می‌گیرد:

  1. تابعی که محاسبه را انجام می‌دهد.
  2. آرایه‌ای از وابستگی‌ها.

تابع فقط زمانی اجرا می‌شود که یکی از وابستگی‌های موجود در آرایه تغییر کند. در غیر این صورت، useMemo مقدار مموایز شده قبلی را برمی‌گرداند.

مثال: محاسبه دنباله فیبوناچی

دنباله فیبوناچی یک مثال کلاسیک از یک محاسبه سنگین است. بیایید یک کامپوننت بسازیم که n-امین عدد فیبوناچی را با استفاده از useMemo محاسبه می‌کند.


import React, { useState, useMemo } from 'react';

function Fibonacci({ n }) {
  const fibonacciNumber = useMemo(() => {
    console.log('Calculating Fibonacci...'); // نشان می‌دهد که محاسبه چه زمانی اجرا می‌شود
    function calculateFibonacci(num) {
      if (num <= 1) {
        return num;
      }
      return calculateFibonacci(num - 1) + calculateFibonacci(num - 2);
    }
    return calculateFibonacci(n);
  }, [n]);

  return 

Fibonacci({n}) = {fibonacciNumber}

; } function App() { const [number, setNumber] = useState(5); return (
setNumber(parseInt(e.target.value))} />
); } export default App;

در این مثال، تابع calculateFibonacci فقط زمانی اجرا می‌شود که prop n تغییر کند. بدون useMemo, این تابع در هر بار رندر مجدد کامپوننت Fibonacci اجرا می‌شد، حتی اگر n ثابت باقی می‌ماند. تصور کنید این محاسبه در یک داشبورد مالی جهانی اتفاق می‌افتد - هر تیک بازار باعث یک محاسبه مجدد کامل می‌شود و منجر به تأخیر قابل توجهی می‌گردد. useMemo از این امر جلوگیری می‌کند.

معرفی useCallback: مموایز کردن توابع

useCallback یک هوک دیگر React است که توابع را مموایز می‌کند. این هوک از ایجاد یک نمونه جدید از تابع در هر بار رندر جلوگیری می‌کند، که به ویژه هنگام ارسال callbackها به عنوان props به کامپوننت‌های فرزند مفید است.

چه زمانی از useCallback استفاده کنیم

useCallback چگونه کار می‌کند

useCallback دو آرگومان می‌گیرد:

  1. تابعی که باید مموایز شود.
  2. آرایه‌ای از وابستگی‌ها.

تابع فقط زمانی دوباره ایجاد می‌شود که یکی از وابستگی‌های موجود در آرایه تغییر کند. در غیر این صورت، useCallback همان نمونه تابع قبلی را برمی‌گرداند.

مثال: مدیریت کلیک روی یک دکمه

بیایید یک کامپوننت با یک دکمه بسازیم که یک تابع callback را فراخوانی می‌کند. ما از useCallback برای مموایز کردن تابع callback استفاده خواهیم کرد.


import React, { useState, useCallback } from 'react';

function Button({ onClick, children }) {
  console.log('Button re-rendered'); // نشان می‌دهد که دکمه چه زمانی دوباره رندر می‌شود
  return ;
}

const MemoizedButton = React.memo(Button);

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

  const handleClick = useCallback(() => {
    console.log('Button clicked');
    setCount((prevCount) => prevCount + 1);
  }, []); // آرایه وابستگی خالی به این معنی است که تابع فقط یک بار ایجاد می‌شود

  return (
    

Count: {count}

Increment
); } export default App;

در این مثال، تابع handleClick فقط یک بار ایجاد می‌شود زیرا آرایه وابستگی خالی است. هنگامی که کامپوننت App به دلیل تغییر state count دوباره رندر می‌شود، تابع handleClick ثابت باقی می‌ماند. کامپوننت MemoizedButton که با React.memo پوشانده شده است، فقط در صورتی دوباره رندر می‌شود که props آن تغییر کند. از آنجایی که prop onClick (یعنی handleClick) ثابت باقی می‌ماند، کامپوننت Button به طور غیرضروری دوباره رندر نمی‌شود. یک اپلیکیشن نقشه تعاملی را تصور کنید. هر بار که کاربر تعامل می‌کند، ده‌ها کامپوننت دکمه ممکن است تحت تأثیر قرار گیرند. بدون useCallback، این دکمه‌ها به طور غیرضروری دوباره رندر می‌شوند و تجربه‌ای کند ایجاد می‌کنند. استفاده از useCallback تعامل روان‌تری را تضمین می‌کند.

معرفی React.memo: مموایز کردن کامپوننت‌ها

React.memo یک کامپوننت مرتبه بالاتر (HOC) است که یک کامپوننت تابعی را مموایز می‌کند. این کار از رندر مجدد کامپوننت در صورتی که props آن تغییر نکرده باشد، جلوگیری می‌کند. این شبیه به PureComponent برای کامپوننت‌های کلاسی است.

چه زمانی از React.memo استفاده کنیم

React.memo چگونه کار می‌کند

React.memo یک کامپوننت تابعی را در بر می‌گیرد و props قبلی و بعدی را به صورت سطحی (shallowly) مقایسه می‌کند. اگر propsها یکسان باشند، کامپوننت دوباره رندر نخواهد شد.

مثال: نمایش پروفایل کاربر

بیایید یک کامپوننت بسازیم که پروفایل یک کاربر را نمایش می‌دهد. ما از React.memo برای جلوگیری از رندرهای مجدد غیرضروری در صورتی که داده‌های کاربر تغییر نکرده باشد، استفاده خواهیم کرد.


import React from 'react';

function UserProfile({ user }) {
  console.log('UserProfile re-rendered'); // نشان می‌دهد که کامپوننت چه زمانی دوباره رندر می‌شود
  return (
    

Name: {user.name}

Email: {user.email}

); } const MemoizedUserProfile = React.memo(UserProfile, (prevProps, nextProps) => { // تابع مقایسه سفارشی (اختیاری) return prevProps.user.id === nextProps.user.id; // فقط در صورتی دوباره رندر کن که شناسه کاربر تغییر کند }); function App() { const [user, setUser] = React.useState({ id: 1, name: 'John Doe', email: 'john.doe@example.com', }); const updateUser = () => { setUser({ ...user, name: 'Jane Doe' }); // تغییر نام }; return (
); } export default App;

در این مثال، کامپوننت MemoizedUserProfile فقط در صورتی دوباره رندر می‌شود که prop user.id تغییر کند. حتی اگر سایر ویژگی‌های شیء user تغییر کنند (مانند نام یا ایمیل)، کامپوننت دوباره رندر نخواهد شد مگر اینکه شناسه متفاوت باشد. این تابع مقایسه سفارشی در `React.memo` امکان کنترل دقیق بر زمان رندر مجدد کامپوننت را فراهم می‌کند. یک پلتفرم رسانه اجتماعی با پروفایل‌های کاربری که دائماً در حال به‌روزرسانی هستند را در نظر بگیرید. بدون `React.memo`، تغییر وضعیت یا عکس پروفایل کاربر باعث رندر مجدد کامل کامپوننت پروفایل می‌شود، حتی اگر جزئیات اصلی کاربر ثابت باقی بماند. `React.memo` امکان به‌روزرسانی‌های هدفمند را فراهم کرده و عملکرد را به طور قابل توجهی بهبود می‌بخشد.

ترکیب useMemo، useCallback و React.memo

این سه تکنیک زمانی بیشترین تأثیر را دارند که با هم استفاده شوند. useMemo محاسبات سنگین را مموایز می‌کند، useCallback توابع را مموایز می‌کند و React.memo کامپوننت‌ها را مموایز می‌کند. با ترکیب این تکنیک‌ها، می‌توانید تعداد رندرهای مجدد غیرضروری را در اپلیکیشن React خود به طور قابل توجهی کاهش دهید.

مثال: یک کامپوننت پیچیده

بیایید یک کامپوننت پیچیده‌تر بسازیم که نحوه ترکیب این تکنیک‌ها را نشان دهد.


import React, { useState, useCallback, useMemo } from 'react';

function ListItem({ item, onUpdate, onDelete }) {
  console.log(`ListItem ${item.id} re-rendered`); // نشان می‌دهد که کامپوننت چه زمانی دوباره رندر می‌شود
  return (
    
  • {item.text}
  • ); } const MemoizedListItem = React.memo(ListItem); function List({ items, onUpdate, onDelete }) { console.log('List re-rendered'); // نشان می‌دهد که کامپوننت چه زمانی دوباره رندر می‌شود return (
      {items.map((item) => ( ))}
    ); } const MemoizedList = React.memo(List); function App() { const [items, setItems] = useState([ { id: 1, text: 'Item 1' }, { id: 2, text: 'Item 2' }, { id: 3, text: 'Item 3' }, ]); const handleUpdate = useCallback((id) => { setItems((prevItems) => prevItems.map((item) => item.id === id ? { ...item, text: `Updated ${item.text}` } : item ) ); }, []); const handleDelete = useCallback((id) => { setItems((prevItems) => prevItems.filter((item) => item.id !== id)); }, []); const memoizedItems = useMemo(() => items, [items]); return (
    ); } export default App;

    در این مثال:

    این ترکیب از تکنیک‌ها تضمین می‌کند که کامپوننت‌ها فقط در صورت لزوم دوباره رندر می‌شوند و منجر به بهبود قابل توجه عملکرد می‌شود. یک ابزار مدیریت پروژه در مقیاس بزرگ را تصور کنید که در آن لیست‌های وظایف دائماً در حال به‌روزرسانی، حذف و مرتب‌سازی مجدد هستند. بدون این بهینه‌سازی‌ها، هر تغییر کوچکی در لیست وظایف باعث ایجاد یک زنجیره از رندرهای مجدد می‌شود و اپلیکیشن را کند و غیرپاسخگو می‌کند. با استفاده استراتژیک از useMemo، useCallback و React.memo، اپلیکیشن می‌تواند حتی با داده‌های پیچیده و به‌روزرسانی‌های مکرر، کارآمد باقی بماند.

    تکنیک‌های بهینه‌سازی اضافی

    در حالی که useMemo، useCallback و React.memo ابزارهای قدرتمندی هستند، تنها گزینه‌ها برای بهینه‌سازی عملکرد React نیستند. در اینجا چند تکنیک اضافی برای در نظر گرفتن وجود دارد:

    ملاحظات جهانی برای بهینه‌سازی

    هنگام بهینه‌سازی اپلیکیشن‌های React برای مخاطبان جهانی، مهم است که عواملی مانند تأخیر شبکه، قابلیت‌های دستگاه و بومی‌سازی را در نظر بگیرید. در اینجا چند نکته وجود دارد:

    نتیجه‌گیری

    بهینه‌سازی عملکرد اپلیکیشن React برای ارائه یک تجربه کاربری روان و پاسخگو بسیار مهم است. با تسلط بر تکنیک‌هایی مانند useMemo، useCallback و React.memo و با در نظر گرفتن استراتژی‌های بهینه‌سازی جهانی، می‌توانید اپلیکیشن‌های React با کارایی بالا بسازید که برای پاسخگویی به نیازهای یک پایگاه کاربری متنوع مقیاس‌پذیر باشند. به یاد داشته باشید که اپلیکیشن خود را برای شناسایی گلوگاه‌های عملکرد پروفایل کنید و این تکنیک‌های بهینه‌سازی را به صورت استراتژیک به کار ببرید. بهینه‌سازی زودهنگام انجام ندهید – بر روی مناطقی تمرکز کنید که می‌توانید بیشترین تأثیر را داشته باشید.

    این راهنما یک پایه محکم برای درک و پیاده‌سازی بهینه‌سازی‌های عملکرد React فراهم می‌کند. همانطور که به توسعه اپلیکیشن‌های React ادامه می‌دهید، به یاد داشته باشید که عملکرد را در اولویت قرار دهید و به طور مداوم به دنبال راه‌های جدید برای بهبود تجربه کاربری باشید.