Functional Component — هي طريقة لإنشاء مكونات React باستخدام دوال JavaScript العادية، والتي أصبحت المعيار بعد إصدار React 16.8 وظهور الهوكس. تقبل المكونات الوظيفية props وتعيد عناصر React دون الحاجة إلى وراثة React.Component. وفقاً لـ React، 2024، 97% من المكونات الجديدة في نظام React البيئي تُكتب كدوال.
النقاط الرئيسية
Functional Component هو مكون React يُعرف كدالة تقبل كائن props وتعيد عنصر React. قبل React 16.8، كانت هذه المكونات تسمى عديمة الحالة (stateless) لأنها لم تكن تستطيع إدارة الحالة الداخلية.
مع ظهور الهوكس في React 16.8 (فبراير 2019)، حصلت المكونات الوظيفية على إمكانية الوصول إلى الحالة (useState)، التأثيرات الجانبية (useEffect)، السياق (useContext) والمراجع (useRef). مصطلح ‘عديمة الحالة’ أصبح قديماً — المكونات الوظيفية الحديثة تدير الحالة بشكل كامل.
توصي React رسمياً بالمكونات الوظيفية كـ طريقة رئيسية لإنشاء المكونات. جميع الوثائق على react.dev، الأمثلة، الدروس التعليمية وواجهات API الجديدة (Server Components, Actions) مبنية على النهج الوظيفي. لم تتم إزالة المكونات الصفية، لكن الميزات الجديدة لـ React متاحة فقط من خلال الهوكس.
أبسط مكون وظيفي هو دالة تعيد JSX. يقبل props كوسيط، لا يتطلب constructor أو استدعاء super أو ربط this. الـ props متاحة مباشرة من خلال وسيط الدالة — لا حاجة لـ this.props.
// Functional component without state
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
// Arrow function (common variant)
const Greeting = ({ name }) => (
<h1>Hello, {name}!</h1>
);
لإضافة حالة، استخدم useState. يعيد الهوكس مجموعة من قيمتين: الحالة الحالية ودالة التحديث. على عكس this.setState في الصفوف، يستبدل useState القيمة بالكامل بدلاً من دمجها مع السابقة.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
الهوكس هي أساس React الحديث. كل هوكس يحل مهمة محددة: useState — الحالة، useEffect — التأثيرات الجانبية، useContext — الوصول إلى السياق، useRef — مراجع عناصر DOM، useCallback و useMemo — التخزين المؤقت.
يستبدل useEffect كلاً من componentDidMount و componentDidUpdate و componentWillUnmount معاً. الوسيط الأول هو دالة الاستدعاء مع التأثير، والثاني هو مصفوفة التبعيات. إذا كانت المصفوفة فارغة، يتم تنفيذ التأثير مرة واحدة بعد التثبيت. إذا تم تحديد تبعيات، يتم التنفيذ عندما تتغير أي منها.
import React, { useState, useEffect } from 'react';
function UserData({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
let cancelled = false;
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => {
if (!cancelled) setUser(data);
});
// Cleanup - analog of componentWillUnmount
return () => { cancelled = true; };
}, [userId]); // Dependency
return <div>{user?.name}</div>;
}
الميزة الرئيسية للمكونات الوظيفية هي إعادة استخدام المنطق من خلال الهوكس المخصصة. بينما في المكون الصفي كان المنطق يتكرر بين componentDidMount و componentDidUpdate، في المكون الوظيفي يتم استخراجه في دالة منفصلة ببادئة use. الهوكس المخصصة هي البديل الرئيسي لـ HOC و render props.
توصي React بـ التركيب بدلاً من الوراثة لإعادة استخدام الكود بين المكونات. المكونات الوظيفية مثالية للتركيب: يمكن لمكون واحد أن يحتوي على عدة مكونات أخرى، ويمرر لها props و children.
نمط children — عندما يستقبل المكون عناصر فرعية من خلال prop children — يتم تنفيذه بشكل طبيعي: function Layout({ children }). يتم تنفيذ ما يعادل slots في Vue من خلال props مكونات مسماة: function Page({ header, sidebar, content }).
الوراثة نادراً ما تستخدم في React. حتى المكونات الصفية، التي تدعم extends تقنياً، نادراً ما تشكل تسلسلات هرمية أعمق من مستوى واحد. المكونات الوظيفية مع التركيب تغطي تماماً احتياجات إعادة استخدام الكود دون وراثة.
تأتي المكونات الوظيفية مع آليات تحسين مدمجة. React.memo — ما يعادل PureComponent للدوال: يمنع إعادة التصيير إذا لم تتغير props (مقارنة سطحية). useMemo يخزن نتائج الحسابات بين عمليات التصيير.
import React, { useMemo } from 'react';
// React.memo - memoize component
const ExpensiveList = React.memo(({ items }) => {
return <ul>
{items.map(item =>
<li key={item.id}>{item.name}</li>
)}
</ul>;
});
// useMemo - caching result
function Dashboard({ transactions }) {
const summary = useMemo(() => {
return transactions.reduce((acc, t) => acc + t.amount, 0);
}, [transactions]);
return <p>Total: {summary}</p>;
}
useCallback يخزن دوال الاستدعاء مؤقتاً حتى لا يتم إعادة إنشائها في كل تصيير. هذا أمر حاسم عند تمرير دوال إلى مكونات فرعية مغلفة بـ React.memo: بدون useCallback، سيتم إعادة تصيير المكون الفرعي في كل مرة لأن مرجع الدالة يتغير.
الفرق بين النهجين يتجاوز بناء الجملة. المكونات الوظيفية هي closures: الحالة والتأثيرات مرتبطة بتصيير محدد. المكونات الصفية تستخدم this: الحالة تؤخذ دائماً من this.state، والتي قد تكون قديمة وقت تنفيذ دالة استدعاء غير متزامنة.
| الجانب | وظيفي | صفي |
|---|---|---|
| الحالة | useState (معزولة) | this.state + this.setState |
| التأثيرات | useEffect مع تبعيات | componentDidMount + componentDidUpdate |
| السياق | useContext | Context.Consumer أو static contextType |
| التحسين | React.memo + useMemo | PureComponent + shouldComponentUpdate |
| إعادة الاستخدام | هوكس مخصصة | HOC / Render props |
| this | لا يوجد | bind في constructor |
توفر المكونات الوظيفية تدفق تنفيذ خطي. في المكون الصفي، غالباً ما يكون المنطق المرتبط مبعثراً عبر طرق دورة حياة متعددة. على سبيل المثال، يتم إعداد اشتراك WebSocket في componentDidMount وإزالته في componentWillUnmount. في المكون الوظيفي، كلتا العمليتين في useEffect واحد مع دالة تنظيف للإرجاع.
يعمل TypeScript بشكل أكثر طبيعية مع المكونات الوظيفية مقارنة بالصفوف. كتابة props — واجهة لوسيط الدالة. نوع الإرجاع هو JSX.Element أو ReactNode. يستنتج useState النوع تلقائياً من القيمة الأولية.
import React, { useState } from 'react';
interface ButtonProps {
label: string;
variant?: 'primary' | 'secondary';
onClick: () => void;
}
const Button: React.FC<ButtonProps> =
({ label, variant = 'primary', onClick }) => (
<button
className={`btn btn-${variant}`}
onClick={onClick}
>
{label}
</button>
);
يسمح TypeScript الحديث بكتابة useReducer بأنواع union متمايزة، والعوامل العامة (Generics) في الهوكس المخصصة، والتحقق الصارم من children من خلال React.PropsWithChildren. توفر المكونات الوظيفية مع TypeScript أماناً كاملاً للأنواع دون تجريدات إضافية.
الأسئلة المتكررة
المكونات الوظيفية أبسط: لا يوجد constructor أو bind أو this أو طرق دورة حياة مبعثرة. تسمح الهوكس بتجميع المنطق المرتبط. تستثمر React مواردها في تطوير الهوكس، وليس الصفوف. Server Components والميزات الجديدة متاحة فقط في الدوال.
نعم، من خلال useEffect مع مؤقت داخلي ودالة تنظيف لـ clearInterval. انتبه إلى closure: إذا كنت تزيد عداداً، استخدم الصيغة الوظيفية لـ setState: setCount(c => c + 1) لتجنب الاعتماد على القيمة القديمة في closure.
استخدم useRef لتخزين القيمة السابقة. قم بتحديث المرجع في useEffect بعد كل تصيير. يساعد هوكس مخصص usePrevious في المقارنة النظيفة: const prev = usePrevious(value);
React.memo هو HOC لتخزين مكون كامل مؤقتاً: يمنع إعادة التصيير إذا لم تتغير props. useMemo هو هوكس لتخزين قيمة محددة مؤقتاً داخل المكون: يخزن نتيجة دالة بين التصييرات حسب مصفوفة التبعيات.
الطريقة الأبسط هي useState مع تهيئة من props + useEffect مع تبعية على props للمزامنة. للحالات النادرة، توصي React باستخدام key لإجبار إعادة إنشاء المكون عندما تتغير بيانات الإدخال.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.