useMemo و useCallback في React: متى ولماذا؟

أحيانًا يعيد React تنفيذ عمليات حسابية أو إعادة إنشاء دوال مع كل رندر. في التطبيقات الكبيرة، هذا قد يسبب بطء غير ضروري.

هنا تأتي فائدة useMemo و useCallback لتحسين الأداء.

ما الفرق بين useMemo و useCallback؟

useMemo يحفظ نتيجة عملية حسابية، بينما useCallback يحفظ نفس الدالة بين الرندرات.

التعريف البسيط: useMemo للنتائج، useCallback للدوال.

مثال 1: استخدام useMemo لحساب ثقيل

import { useMemo, useState } from "react";

function ExpensiveCalc() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState("");

  const total = useMemo(() => {
    // عملية حسابية ثقيلة
    let sum = 0;
    for (let i = 0; i < 1000000; i++) {
      sum += i;
    }
    return sum + count;
  }, [count]);

  return (
    <div>
      <p>النتيجة: {total}</p>
      <button onClick={() => setCount(count + 1)}>زيادة</button>
      <input value={text} onChange={(e) => setText(e.target.value)} />
    </div>
  );
}

هنا لن يُعاد الحساب الثقيل إلا عند تغيّر count، بينما تغيير text لا يعيد الحساب.

السبب: وضعنا count فقط داخل dependency array، لذلك useMemo يتجاهل تغيّر text. هذا مفيد عندما يكون لديك input يغيّر الواجهة كثيرًا لكنك لا تريد إعادة حساب مكلف في كل مرة.

خطوة بخطوة: عند كتابة المستخدم في input، يتغيّر text فيعيد React الرندر، لكن useMemo لا يعيد الحساب الثقيل لأن count لم يتغيّر. النتيجة: الواجهة تتحدث بسرعة بدون تكلفة إضافية.

مثال 2: useCallback لتثبيت دالة

import { useCallback, useState } from "react";

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

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

  return <Child onClick={handleClick} />;
}

هنا نحافظ على نفس الدالة بين الرندرات، مما يمنع إعادة رندر غير ضروري في Child.

بدون useCallback، يتم إنشاء دالة جديدة في كل رندر، فيعتقد المكوّن الفرعي أن الـ props تغيّرت ويعيد الرندر. تثبيت الدالة يقلل هذا النوع من الرندرات غير الضرورية.

عمليًا: المكوّن Child يعتمد على onClick. إذا تغيّر المرجع (حتى لو المنطق نفسه) سيعيد الرندر. useCallback يثبت المرجع طالما لم تتغير dependencies.

متى لا أستخدم useMemo أو useCallback؟

  • إذا كان التطبيق صغيرًا ولا يعاني من بطء.
  • إذا كانت الحسابات بسيطة جدًا.
  • إذا لم يكن هناك مكوّنات فرعية تعتمد على الدوال.

أخطاء شائعة

  • استخدام useMemo في كل مكان بدون قياس الأداء.
  • نسيان وضع القيم الصحيحة في dependency array.
  • الاعتقاد أن useCallback يمنع كل إعادة رندر دائمًا.

الأسئلة الشائعة — FAQ

ما الفرق بين useMemo و useCallback؟

useMemo يحفظ نتيجة حساب، و useCallback يحفظ نفس الدالة.

متى أستخدم useMemo؟

عند وجود حساب ثقيل يحتاج تحسين.

متى أستخدم useCallback؟

عند تمرير دوال لمكوّنات فرعية لتجنب إعادة رندر غير ضروري.

هل useMemo يجعل التطبيق أسرع دائمًا؟

لا، قد يضيف تعقيدًا إذا لم يكن هناك مشكلة أداء حقيقية.

هل useCallback بديل عن useMemo؟

لا، useCallback هو useMemo للدوال فقط.

التالي: سننتقل لدرس useReducer وكيف ننظم الحالة المعقدة.
المحرر الذكي

اكتب الكود وشاهد النتيجة فوراً

جرب الآن مجاناً
قناة ديف عربي

تابع أحدث الدروس والتحديثات مباشرة على واتساب

انضم الآن