useCallback وuseMemo لتحسين الأداء
احفظ دوال رد الاتصال مؤقتًا باستخدام useCallback لمنع إعادة تصيير المكوّنات الفرعية دون حاجة، وخزّن القيم المحسوبة المكلفة باستخدام useMemo.
useCallback وuseMemo لتحسين الأداء درس مجاني في React Native Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في React Native Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة React Native Academy 4 دروس في المجموع.
بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.
The Re-Render Problem
Every time a component re-renders in React, all values created inside the function body are recreated. This includes objects, arrays, and most importantly — functions. If a recreated function or value is passed as a prop to a child component, the child sees a new reference and re-renders, even when the logical value has not changed.
What is useCallback?
useCallback(fn, deps) returns a memoized version of the callback function that only changes if one of the dependencies has changed. Wrapping a callback in useCallback preserves the same function reference across renders, preventing unnecessary re-renders in child components that receive it as a prop.
import { useCallback } from 'react';
function Parent() {
const [count, setCount] = useState(0);
// handlePress is the SAME function reference between renders
// as long as count does not change
const handlePress = useCallback(() => {
console.log('Pressed, count is:', count);
}, [count]);
return <Child onPress={handlePress} />;
}useCallback with React.memo
useCallback is most effective when paired with React.memo on the child component. Without React.memo the child re-renders anyway regardless of prop reference equality. The combination of React.memo on the child and useCallback on the parent callback prevents re-renders when neither the behavior nor the data has changed.
const ChildButton = React.memo(({ onPress, label }) => (
<Button title={label} onPress={onPress} />
));
function Parent() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
// ChildButton will NOT re-render when text changes
const handleCount = useCallback(() => setCount(c => c + 1), []);
return (
<>
<TextInput value={text} onChangeText={setText} />
<ChildButton label='Count' onPress={handleCount} />
</>
);
}What is useMemo?
useMemo(computeFn, deps) memoizes the result of an expensive computation. React calls computeFn on the first render and caches its return value. On subsequent renders it returns the cached value unless a dependency has changed. This avoids repeating heavy calculations every render.
import { useMemo } from 'react';
function ProductList({ products, category }) {
// Only recomputes when products or category changes
const filtered = useMemo(
() => products.filter((p) => p.category === category),
[products, category]
);
return <FlatList data={filtered} renderItem={renderItem} />;
}useMemo for Stable Object References
Objects and arrays created inline in JSX are new references on every render. If passed to a memoized child, they defeat memoization. Wrap them in useMemo to create a stable reference that only changes when the underlying data changes. This is especially important for style arrays and config objects.
function Chart({ data, color }) {
// New object on every render without useMemo
const chartConfig = useMemo(() => ({
backgroundColor: color,
dataPoints: data.map((d) => d.value),
}), [data, color]);
return <ChartComponent config={chartConfig} />;
}Dependency Arrays: Getting Them Right
Both useCallback and useMemo require accurate dependency arrays. Include every value from the component scope that is used inside the memoized function or computation. Missing a dependency causes the memoized value to use a stale closure; listing too many causes unnecessary recomputation. ESLint's exhaustive-deps rule helps enforce correctness.
// Wrong: missing userId dependency — stale closure bug
const fetchUser = useCallback(() => fetch('/user/' + userId), []);
// Correct: userId is listed
const fetchUser = useCallback(() => fetch('/user/' + userId), [userId]);When NOT to Use useCallback
useCallback has a cost: React stores the function in memory and checks the dependency array on every render. For simple handlers that are not passed to memoized children, the overhead of useCallback exceeds the benefit. Use it selectively — only when the child component is wrapped in React.memo and props equality matters for performance.
// Unnecessary: Button re-renders anyway; no child is memoized
const handlePress = useCallback(() => setVisible(true), []);
// Fine without useCallback in this case
const handlePress = () => setVisible(true);useMemo for Expensive Transformations
Use useMemo when a computation takes noticeable time — sorting large arrays, parsing complex data, running statistical calculations. The rule of thumb: if the computation takes more than a millisecond and runs on every render, consider memoizing it. For trivial operations (adding two numbers), the memoization overhead is larger than the computation itself.
const sortedAndFiltered = useMemo(() => {
return items
.filter((item) => item.status === selectedStatus)
.sort((a, b) => b.createdAt - a.createdAt)
.slice(0, 100);
}, [items, selectedStatus]);useCallback for renderItem in FlatList
Wrapping the renderItem function of a FlatList in useCallback prevents a new function reference from being created on every parent render, which would cause every visible FlatList row to re-render. This is one of the most impactful performance wins in list-heavy React Native apps.
const renderItem = useCallback(({ item }) => (
<ProductCard
product={item}
onPress={handleSelectProduct}
/>
), [handleSelectProduct]); // handleSelectProduct also memoized
<FlatList
data={products}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>Measuring the Impact
Before adding memoization everywhere, measure the actual impact using the React DevTools Profiler. Record an interaction, look at the flame chart to identify components that re-render unnecessarily, and only add useCallback or useMemo where the profiler shows a real bottleneck. Premature optimization adds code complexity with no measurable benefit.
Summary Comparison
Remember the key difference: useCallback memoizes a function (prevents recreating the function reference), while useMemo memoizes a computed value (prevents re-running an expensive calculation). Both accept a dependency array and only recompute when the listed dependencies change.
// useCallback — memoize a function
const fn = useCallback(() => doSomething(a, b), [a, b]);
// useMemo — memoize a computed value
const val = useMemo(() => computeExpensive(a, b), [a, b]);
// Relationship: useCallback(fn, deps) === useMemo(() => fn, deps)Quick Check
Test your understanding of useCallback and useMemo for performance from this lesson.
Lesson Recap
In this lesson you learned: useCallback memoizes a function reference to prevent unnecessary child re-renders, useMemo memoizes an expensive computed value to skip re-calculation on every render, and both work best when combined with React.memo and accurate dependency arrays. Next up we explore writing custom hooks to share stateful logic between components.
الأسئلة الشائعة
هل درس «useCallback وuseMemo لتحسين الأداء» مجاني؟
نعم — نص درس «useCallback وuseMemo لتحسين الأداء» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة React Native Academy، انتقل إلى CoddyKit PRO. تتضمن دورة React Native Academy 4 دروس في المجموع.
ماذا ستتعلم في «useCallback وuseMemo لتحسين الأداء»؟
احفظ دوال رد الاتصال مؤقتًا باستخدام useCallback لمنع إعادة تصيير المكوّنات الفرعية دون حاجة، وخزّن القيم المحسوبة المكلفة باستخدام useMemo. تتمرن على React Native Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ React Native Academy؟
لا تُشترط خبرة سابقة. React Native Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «useCallback وuseMemo لتحسين الأداء»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس React Native Academy هذا؟
نعم. كل درس في React Native Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- useRef لعُقد DOM والقيم القابلة للتغيير
- useReducer لمنطق الحالة المعقد
- useCallback وuseMemo لتحسين الأداء
- كتابة Hooks مخصصة