المقدمة:

منذ إصدار React 16.8، قدّمت مكتبة React ميزة Hooks لتسهيل التعامل مع الحالة (state) ودورة حياة المكونات (lifecycle) دون الحاجة إلى كتابة class components.
هذه الميزة جعلت الكود أبسط، وأكثر قابلية لإعادة الاستخدام، وسهّلت بناء مكونات تفاعلية وفعالة.

في هذا الدليل، سنتعرّف على أهم Hooks في React، وكيفية استخدامها مع أمثلة عملية مبسطة.


ما هو الـ Hook في React؟

الـ Hook هو دالة (Function) مدمجة في React تتيح لك “ربط” الكود الخاص بالحالة أو دورة الحياة داخل المكونات الوظيفية.
بكلمات أبسط، بدل ما تستخدم class وتتعامل مع this.state، يمكنك الآن استخدام useState و useEffect داخل مكونات مبنية على الدوال فقط.


1. useState

يُستخدم useState لإدارة الحالة داخل المكونات الوظيفية.
الحالة هي البيانات التي تتغير مع مرور الوقت وتؤثر على شكل واجهة المستخدم.
في السابق، لم يكن بإمكان المكونات الوظيفية أن تحتوي على حالة، لكن useState غيّر هذا تمامًا.

مثال:

import { useState } from "react";

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

  return (
    <div>
      <p>العَدّ الحالي: {count}</p>
      <button onClick={() => setCount(count + 1)}>زيادة</button>
    </div>
  );
}

2. useEffect

يُستخدم useEffect للتعامل مع الجوانب الجانبية (side effects) مثل:

  • جلب البيانات من API
  • تحديث العنوان في المتصفح
  • الاشتراك أو إلغاء الاشتراك في أحداث

بشكل افتراضي، يتم تنفيذ useEffect بعد كل عملية إعادة رسم (render).

مثال:

import { useEffect, useState } from "react";

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => setSeconds((s) => s + 1), 1000);
    return () => clearInterval(interval);
  }, []);

  return <p>مر {seconds} ثانية منذ فتح الصفحة</p>;
}

3. useContext

يسمح useContext بمشاركة البيانات بين المكونات دون تمريرها يدويًا عبر Props في كل مستوى.
هذا مفيد جدًا عند التعامل مع إعدادات عامة مثل اللغة أو الثيم أو بيانات المستخدم.

مثال:

import { createContext, useContext } from "react";

const ThemeContext = createContext("light");

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <p>الوضع الحالي: {theme}</p>;
}

4. useRef

يُستخدم useRef للوصول إلى عناصر DOM مباشرة أو لتخزين قيمة لا تؤدي إلى إعادة التصيير (render).
ببساطة، هو كمتغير يمكن أن يحتفظ بقيمته بين عمليات إعادة العرض دون التأثير على الواجهة.

مثال:

import { useRef, useEffect } from "react";

function InputFocus() {
  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} placeholder="سيتم التركيز هنا تلقائيًا" />;
}

5. useMemo

يُستخدم useMemo لتحسين الأداء عن طريق تخزين نتيجة العمليات الثقيلة وعدم إعادة حسابها إلا عندما تتغير القيم التابعة لها.

مثال:

import { useMemo, useState } from "react";

function ExpensiveCalculation() {
  const [num, setNum] = useState(0);

  const squared = useMemo(() => {
    console.log("يتم الحساب...");
    return num * num;
  }, [num]);

  return (
    <div>
      <input
        type="number"
        value={num}
        onChange={(e) => setNum(Number(e.target.value))}
      />
      <p>النتيجة: {squared}</p>
    </div>
  );
}

6. useCallback

يشبه useMemo لكنّه يُستخدم لتخزين الدوال بدلًا من القيم.
يساعد في تحسين الأداء عندما تمرر دوال كمُعاملات لمكونات فرعية حتى لا تُعاد إنشاؤها في كل مرة.

مثال:

import { useState, useCallback } from "react";

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

  const increment = useCallback(() => setCount((c) => c + 1), []);

  return <button onClick={increment}>العَدّ: {count}</button>;
}

7. useReducer

يُعتبر useReducer بديلًا متقدمًا لـ useState، ويُستخدم عندما تصبح الحالة أكثر تعقيدًا وتحتاج إلى إدارة منطق محدد للتحديث.

مثال:

import { useReducer } from "react";

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}

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

  return (
    <>
      <p>العدّ: {state.count}</p>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </>
  );
}

خلاصة

باستخدام Hooks، أصبح بناء المكونات في React أسهل وأوضح.
تستطيع الآن إدارة الحالة، تنفيذ العمليات الجانبية، ومشاركة البيانات بين المكونات — كل ذلك دون الحاجة إلى استخدام الـ class components.

ابدأ بتجربة useState وuseEffect أولاً، ثم انتقل إلى باقي الـ Hooks حسب احتياج مشروعك.