React Hooks — ما هي، الخطافات الرئيسية وقواعد الاستخدام

المؤلف: IT Sectr نُشر: 2026-07-04 وقت القراءة: 10 دق

React Hooks هي وظائف تتيح لك استخدام الحالة والتأثيرات والسياق وميزات React الأخرى في المكونات الوظيفية، دون كتابة فئات. تم تقديمها في React 16.8، وغيرت الخطافات نهج التطوير بشكل جذري، لتحل محل الأنماط المعقدة مثل HOC و render props. وفقًا لـ React، 2024، هناك 15 خطافًا مدمجًا تغطي جميع سيناريوهات إدارة المكونات.

الخلاصة

  • الخطافات — وظائف لربط ميزات React بالمكونات الوظيفية دون extends Component.
  • useState — الخطاف الأساسي لإدارة الحالة، يعيد قيمة ومُعيّنًا.
  • useEffect — للتأثيرات الجانبية: طلبات API، الاشتراكات، المؤقتات، معالجات DOM.
  • useContext — للوصول إلى سياق React دون أغلفة Consumer و static contextType.
  • قواعد الخطافات — الاستدعاء فقط في المستوى الأعلى وداخل المكونات الوظيفية أو الخطافات المخصصة فقط.

ما هي خطافات React؟

خطافات React هي مجموعة من الوظائف المدمجة في React التي تتيح لك «التوصيل» بالآليات الداخلية للإطار دون إنشاء فئات. قبل React 16.8، كانت المكونات الوظيفية تستطيع فقط قبول props وإرجاع JSX — أي منطق معقد كان يتطلب مكون فئة.

مشكلة المكونات الفئوية هي تقسيم المنطق المرتبط. الكود المرتبط بكيان واحد (مثل اشتراك WebSocket) كان يُقسَّم قسريًا بين componentDidMount و componentDidUpdate و componentWillUnmount. تحل الخطافات هذا: يتم تجميع كل المنطق في useEffect واحد.

المشكلة الثانية هي إعادة استخدام المنطق. لإعادة استخدام منطق الحالة بين المكونات الفئوية، كان عليك تطبيق HOC (مكونات عالية المستوى) أو render props — كلا النمطين خلقا تداخلًا إضافيًا في شجرة المكونات. تحل الخطافات المخصصة هذه المشكلة دون تداخل.

useState — إدارة الحالة

useState هو الخطاف الأكثر أساسية. يأخذ قيمة أولية ويعيد زوجًا: القيمة الحالية ودالة لتحديثها. على عكس this.setState في الفئات، لا يدمج useState الكائنات — الحالة الجديدة تحل محل الحالة السابقة بالكامل لاستدعاء useState معين.

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

function Form() {
  const [text, setText] = useState('');
  const [submitting, setSubmitting] = useState(false);

  async function handleSubmit() {
    setSubmitting(true);
    await fetch('/api/submit', {
      method: 'POST',
      body: JSON.stringify({ text })
    });
    setSubmitting(false);
  }

  return (
    <div>
      <input
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <button onClick={handleSubmit}
        disabled={submitting}>
        {submitting ? 'Saving...' : 'Submit'}
      </button>
    </div>
  );
}

الصيغة الوظيفية لـ setState

يمكن لمُعيّن useState قبول دالة تستقبل القيمة السابقة وتعيد قيمة جديدة. الصيغة الوظيفية إلزامية عندما تُحسب الحالة الجديدة من الحالة السابقة ومن الممكن استدعاءات setState مجمعة — كل استدعاء سيحصل على القيمة السابقة الحالية.

useEffect — التأثيرات الجانبية ودورة الحياة

useEffect هو خطاف لأداء التأثيرات الجانبية في المكونات الوظيفية. يأخذ وسيطين: دالة التأثير ومصفوفة التبعيات. ينفذ React التأثير بعد كل عرض، ولكن عند تحديد التبعيات — فقط عندما تتغير أي منها.

مصفوفة تبعيات فارغة [] تعني أن التأثير يُنفَّذ مرة واحدة بعد العرض الأول (مماثل لـ componentDidMount). إرجاع دالة من التأثير هي عملية تنظيف تُنفَّذ عند إلغاء التثبيت (مماثل لـ componentWillUnmount) وقبل إعادة تنفيذ التأثير.

js
import React, { useState, useEffect } from 'react';

function ChatRoom({ roomId }) {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const socket = new WebSocket(`wss://chat/${roomId}`);

    socket.onmessage = (event) => {
      setMessages(prev => [...prev, JSON.parse(event.data)]);
    };

    // التنظيف - إغلاق المقبس
    return () => socket.close();
  }, [roomId]);

  return <ul>
    {messages.map((msg, i) =>
      <li key={i}>{msg.text}</li>
    )}
  </ul>;
}

تبعيات useEffect هي الرابط الوحيد بين التأثير والعالم الخارجي. إذا استخدم التأثير متغيرًا من props أو الحالة، يجب أن يكون في مصفوفة التبعيات. تجاهل هذه القاعدة هو مصدر أخطاء مع closures القديمة.

useContext — الوصول إلى السياق

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

قبل useContext، كان الوصول إلى السياق في المكونات الوظيفية يتطلب تغليفًا في Context.Consumer، مما خلق تداخلًا. useContext يلغي Consumer تمامًا — فقط استدعِ الخطاف في أي مكان في المكون الوظيفي.

js
import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('فاتح');

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return <button
    className={`btn btn-${theme}`}
  >
    {theme === 'dark' ? 'moon' : '☀️'}
  </button>;
}

useContext ليس بديلاً عن Redux أو الحالة العامة. يوصي React باستخدام السياق للقيم نادرة التغيير — السمة، الإعدادات المحلية، حالة المصادقة. للبيانات التي تُحدَّث بشكل متكرر، كل إعادة عرض ستعيد حساب جميع مستهلكي السياق، مما قد يقلل الأداء.

useReducer — منطق الحالة المعقد

useReducer هو بديل لـ useState للحالات ذات منطق التحديث المعقد. يأخذ دالة مختزلة وحالة أولية، ويعيد الحالة الحالية ودالة dispatch. تستقبل الدالة المختزلة الحالة الحالية والإجراء، وتعيد حالة جديدة — دالة نقية دون تأثيرات جانبية.

useReducer مفيد بشكل خاص عندما تدير إجراءات متعددة (set, reset, increment, addItem) حالة واحدة. بدلاً من استدعاءات useState متعددة بمُعيِّنات مختلفة — مختزل واحد بأنواع إجراءات واضحة. هذا يجعل المنطق قابلًا للتنبؤ وسهل الاختبار.

js
import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + 1 };
    case 'setStep':
      return { ...state, step: action.step };
    case 'reset':
      return { count: 0, step: 1 };
    default:
      throw new Error('Unknown action: ' + action.type);
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, {
    count: 0,
    step: 1
  });

  return (
    <>
      <p>Count: {state.count}</p>
      <button
        onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button
        onClick={() => dispatch({ type: 'reset' })}>Reset</button>
    </>
  );
}

useRef, useMemo, useCallback — التحسين

useRef ينشئ كائنًا قابلًا للتغيير يستمر بين عمليات إعادة العرض. تغيير current لا يؤدي إلى إعادة عرض. الاستخدامات الرئيسية هي الوصول إلى عناصر DOM وتخزين القيم القابلة للتغيير (المؤقتات، القيم السابقة، نسخ المكتبات).

useMemo يحفظ نتيجة دالة. يعيد حساب القيمة فقط عندما تتغير تبعية ما. استخدمه للعمليات الحسابية المكلفة — تصفية المصفوفات الكبيرة، الفرز، تنسيق البيانات. useCallback هو حالة خاصة من useMemo لحفظ الدوال.

js
import React, { useRef, useMemo, useCallback } from 'react';

function SearchPage({ items, query, onItemSelect }) {
  const inputRef = useRef(null);

  // التركيز التلقائي عند التثبيت
  useEffect(() => {
    inputRef.current?.focus();
  }, []);

  // حفظ النتيجة المصفاة
  const filtered = useMemo(() => {
    return items.filter(item =>
      item.name.toLowerCase()
        .includes(query.toLowerCase())
    );
  }, [items, query]);

  // حفظ رد النداء
  const handleSelect = useCallback((id) => {
    onItemSelect(id);
  }, [onItemSelect]);

  return (
    <div>
      <input ref={inputRef}
        value={query}
        onChange={e => setQuery(e.target.value)}
      />
      <ul>
        {filtered.map(item =>
          <li key={item.id}>
            <button
              onClick={() => handleSelect(item.id)}>
              {item.name}
            </button>
          </li>
        )}
      </ul>
    </div>
  );
}

قاعدة مهمة: useRef و useMemo و useCallback هي أدوات تحسين، ليست تركيبات إلزامية. لا تغلف كل شيء في useMemo — قس الأداء أولاً. التحسين المبكر يعقّد الكود. يعرض React المكونات بسرعة؛ useMemo مطلوب فقط عندما تكون العمليات الحسابية مكلفة حقًا (O(n²) أو أعلى).

قواعد الخطافات والأخطاء الشائعة

قدم React قاعدتين صارمتين للخطافات. الأولى: استدعِ الخطافات فقط في المستوى الأعلى — ليس داخل الشروط أو الحلقات أو الدوال المتداخلة. الثانية: استدعِ الخطافات فقط من المكونات الوظيفية لـ React أو الخطافات المخصصة. يتحقق إضافة ESLint eslint-plugin-react-hooks تلقائيًا من كلتا القاعدتين.

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

الخطأما يحدثالحل
خطاف في شرطترتيب الخطافات ينكسرانقل منطق الشرط داخل الخطاف
Stale closureالتأثير يستخدم قيمة قديمةأضف جميع التبعيات إلى المصفوفة
حلقة لا نهائيةuseEffect بدون تبعيات يغير الحالةحدد التبعيات أو استخدم useReducer
تغيير ref في renderتأثير جانبي في جسم الدالةانقل التحويرات إلى useEffect

الخطأ الشائع الثاني هو stale closure في useEffect. إذا استخدم التأثير متغيرًا غير محدد في التبعيات، «يلتقط» التأثير قيمته في وقت إنشاء الإغلاق. الحل هو تضمين جميع المتغيرات المستخدمة دائمًا في مصفوفة التبعيات. إذا كان هناك عدد كبير جدًا من التبعيات، ففكر في تقسيم التأثير إلى عدة أجزاء.

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

لماذا لا يمكن استدعاء الخطافات داخل الشروط؟

React يعتمد على ترتيب استدعاء الخطافات بين عمليات إعادة العرض. إذا تم استدعاء خطاف داخل شرط ولم يتم تشغيله في إحدى عمليات إعادة العرض، تنزاح جميع الخطافات اللاحقة — يختلط حالتها. تحذر قاعدة ESLint hooks/exhaustive-deps من هذا.

ما الفرق بين useEffect و useLayoutEffect؟

useLayoutEffect متزامن ويُتنفَّذ قبل أن يرسم المتصفح التغييرات. useEffect غير متزامن — بعد الرسم. استخدم useLayoutEffect فقط عندما تحتاج إلى قياس أو تغيير DOM قبل أن يرى المستخدم التغييرات (موضع popover، استعادة التمرير).

كيفية إلغاء طلب fetch عند إلغاء التثبيت؟

استخدم AbortController داخل useEffect. أنشئ controller، مرر signal إلى fetch، واستدعِ controller.abort() في دالة التنظيف. للمتصفحات القديمة، استخدم علامة cancelled: return () => { cancelled = true; } مع فحص قبل setState.

ما هو الخطاف المخصص ومتى يتم إنشاؤه؟

الخطاف المخصص هو دالة JavaScript بالبادئة use تستخدم الخطافات المدمجة. أنشئه عندما يتكرر نفس المنطق مع الخطافات في مكونين أو أكثر. أمثلة: useDebounce, useLocalStorage, useMediaQuery. تحل الخطافات المخصصة محل HOC و render props.

لماذا يتم تنفيذ useEffect مرتين في Strict Mode؟

في Strict Mode، يقوم React عمدًا بتثبيت وإلغاء تثبيت المكون مرتين في وضع التطوير للعثور على أخطاء مع التأثيرات غير المُنظَّفة. إذا تمت كتابة التنظيف بشكل صحيح، فإن الاستدعاء المزدوج لا يسبب مشاكل. لا يحدث هذا في وضع الإنتاج.

الملخص

  • React Hooks — وظائف لاستخدام الحالة والتأثيرات والسياق في المكونات الوظيفية، لتحل محل الفئات.
  • useState — خطاف أساسي للحالة المحلية مع مُعيّن وظيفي لتحديثات آمنة.
  • useEffect — خطاف شامل للتأثيرات الجانبية مع مصفوفة تبعيات ودالة تنظيف.
  • useContext — وصول مباشر إلى سياق React دون أغلفة Consumer وتداخل إضافي.
  • useReducer — لمنطق الحالة المعقد مع أنواع إجراءات، بديل لـ Redux داخل مكون واحد.
  • useRef, useMemo, useCallback — أدوات تحسين: مراجع DOM، حفظ القيم واستدعاءات.
  • قاعدة المستوى الأعلى — تقييد صارم باستدعاء الخطافات خارج الشروط والحلقات والدوال المتداخلة.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا