دليل React Hooks: شرح useState و useEffect وكيفية إنشاء Custom Hooks

دقائق القراءة: 6

مقدمة إلى React Hooks

أصبحت Hooks جزءاً أساسياً من تطوير التطبيقات باستخدام React منذ إصدار React 16.8. وتكمن أهميتها في أنها تتيح لك استخدام مزايا متقدمة داخل functional components دون الحاجة إلى كتابة class components.

باستخدام Hooks يمكنك إدارة state، وتنفيذ تأثيرات جانبية بعد تغيّر البيانات، وإعادة استخدام المنطق البرمجي بين المكونات بصورة أكثر أناقة ومرونة.

شرح React Hooks واستخدام useState و useEffect وإنشاء Custom Hooks في React

في هذا الدليل ستتعرّف إلى:

  • مفهوم useState وكيفية استخدامه.
  • طريقة عمل useEffect والتحكم في تشغيله.
  • كيفية إنشاء Custom Hooks لإعادة استخدام المنطق البرمجي.

من المهم التنبيه إلى أن Hooks تُستخدم فقط داخل functional components.

ما هو useState في React؟

أي تطبيق تفاعلي يتعامل مع بيانات قابلة للتغيير بمرور الوقت، مثل اسم المستخدم أو عدد النقرات أو محتوى نموذج الإدخال. في React، يتم التعامل مع هذه القيم من خلال state، وأشهر Hook لهذا الغرض هو useState.

عندما تتغير قيمة state، تقوم React بإعادة تحديث الواجهة DOM تلقائياً لإظهار البيانات الجديدة.

مثال أساسي على useState

import { useState } from "react";

function App() {
  const [name, setName] = useState("Ihechikara");

  const changeName = () => {
    setName("Chikara");
  };

  return (
    <div>
      <p>My name is {name}</p>
      <button onClick={changeName}>Click me</button>
    </div>
  );
}

export default App;

كيف يعمل هذا المثال؟

في البداية نقوم باستيراد Hook:

import { useState } from "react";

ثم ننشئ متغير حالة باسم name ودالة تحديث باسم setName:

const [name, setName] = useState("Ihechikara");

القيمة الأولى name تمثل الحالة الحالية، بينما setName مسؤولة عن تحديثها. أما القيمة المرسلة إلى useState فهي القيمة الابتدائية.

عند الضغط على الزر، يتم تنفيذ الدالة changeName، فتقوم بتحديث الحالة، ما يؤدي إلى إعادة عرض النص بالقيمة الجديدة.

لماذا هذا مهم؟

بدون useState لن تتمكن React من تتبع التغييرات وإعادة عرض الواجهة بشكل صحيح. لذلك يعد هذا Hook نقطة البداية لفهم التفاعل الديناميكي داخل التطبيقات.

استخدام useState في النماذج Forms

أحد أشهر استخدامات useState هو التعامل مع عناصر الإدخال داخل forms. فعند كتابة المستخدم داخل حقل نصي، نحتاج إلى حفظ القيمة الحالية ومزامنتها مع الواجهة.

تهيئة state لحقل إدخال

const [name, setName] = useState("");

هنا بدأنا بقيمة فارغة لأن المستخدم هو من سيملأ الحقل. هذه الطريقة تمنحك تحكماً كاملاً في قيمة الإدخال.

ربط state مع input

return (
  <div>
    <form>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Your Name"
      />
      <p>{name}</p>
    </form>
  </div>
);

في هذا المثال:

  • الخاصية value تربط الحقل بقيمة state.
  • الحدث onChange يلتقط أي تغيير في الإدخال.
  • الدالة setName تحدّث القيمة مباشرة باستخدام e.target.value.

الكود الكامل

import { useState } from "react";

function App() {
  const [name, setName] = useState("");

  return (
    <div>
      <form>
        <input
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
          placeholder="Your Name"
        />
        <p>{name}</p>
      </form>
    </div>
  );
}

export default App;

هذا النمط يسمى controlled components، وهو من أفضل الأساليب لإدارة الحقول في React لأنه يسهّل التحقق من البيانات والتعامل مع الإرسال والأخطاء.

ما هو useEffect في React؟

يُستخدم useEffect لتنفيذ ما يسمى side effects، مثل:

  • جلب البيانات من API.
  • التعامل مع console.
  • تغيير عنوان الصفحة.
  • إضافة أو إزالة event listeners.

بشكل افتراضي، يتم تشغيل useEffect بعد أول عملية render، ثم بعد كل تحديث يحدث للحالة أو الخصائص ذات الصلة.

مثال بسيط على useEffect

import { useState, useEffect } from "react";

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

  useEffect(() => {
    console.log(`You have clicked the button ${count} times`);
  });

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

export default App;

في هذا المثال، يتم تنفيذ useEffect بعد كل تحديث لقيمة count، ويظهر ذلك عبر تسجيل رسالة داخل console.

استيراد أكثر من Hook

import React, { useState, useEffect } from "react";

إذا كنت تحتاج إلى أكثر من Hook داخل المكون نفسه، يمكنك استيرادها معاً كما في المثال السابق.

فهم Dependency Array في useEffect

القوة الحقيقية لـ useEffect تظهر عند استخدام dependency array، وهي المصفوفة التي تحدد متى يجب تشغيل التأثير.

تشغيل التأثير مرة واحدة فقط

إذا مررت مصفوفة فارغة، فسيتم تشغيل التأثير مرة واحدة بعد أول render فقط:

import { useState, useEffect } from "react";

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

  useEffect(() => {
    console.log(`You have clicked the button ${count} times`);
  }, []);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

export default App;

هذا مفيد عند الحاجة إلى تنفيذ عملية تهيئة أولية، مثل تحميل بيانات عند فتح الصفحة.

ربط التأثير بحالة معينة

عندما تريد تشغيل تأثير مرتبط بمتغير محدد فقط، أضف هذا المتغير داخل dependency array.

import { useState, useEffect } from "react";

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

  useEffect(() => {
    console.log(`You have clicked the first button ${count} times`);
  }, [count]);

  const [count2, setCount2] = useState(0);

  useEffect(() => {
    console.log(`You have clicked the second button ${count2} times`);
  }, [count2]);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Click me</button>
      <button onClick={() => setCount2(count2 + 1)}>Click me</button>
    </div>
  );
}

export default App;

في هذا السيناريو:

  • التأثير الأول يعمل فقط عند تغيّر count.
  • التأثير الثاني يعمل فقط عند تغيّر count2.

هذه الآلية تمنحك تحكماً أدق وتقلل من تنفيذ التأثيرات غير الضرورية.

كيفية إنشاء Custom Hooks في React

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

هذا الأسلوب يحسن:

  • تنظيم المشروع.
  • قابلية إعادة الاستخدام.
  • سهولة الصيانة.
  • وضوح الشيفرة البرمجية.

الخطوة الأولى: إنشاء ملف Hook

عند إنشاء Hook مخصص، يجب أن يبدأ اسمه بكلمة use. مثال مناسب:

useFetchData.js

الخطوة الثانية: كتابة منطق الـ Hook

سننشئ Hook يقوم بجلب البيانات من API خارجي بطريقة ديناميكية.

import { useState, useEffect } from 'react'

function useFetchData(url) {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch(url)
      .then((res) => res.json())
      .then((data) => setData(data))
      .catch((err) => console.log(`Error: ${err} `));
  }, [url]);

  return { data };
}

export default useFetchData

شرح مكونات الـ Custom Hook

  • استيراد useState و useEffect.
  • إنشاء حالة data بقيمة ابتدائية null.
  • تنفيذ fetch داخل useEffect.
  • إعادة تشغيل الطلب فقط إذا تغيّرت قيمة url.
  • إرجاع البيانات لاستخدامها داخل أي مكون آخر.

الخطوة الثالثة: استخدام الـ Custom Hook داخل مكون

import useFetchData from './useFetchData'

function Users() {
  const { data } = useFetchData("https://api.github.com/users");

  return (
    <div>
      {data && (
        data.map((user) => (
          <div className="text-white" key={user.id}>
            <h1>{user.login}</h1>
            <p>{user.type}</p>
          </div>
        ))
      )}
    </div>
  )
}

export default Users;

ماذا يحدث هنا؟

يقوم المكون Users باستدعاء useFetchData وتمرير رابط API. بعد جلب البيانات وتحديث state، تعرض React النتائج داخل الواجهة.

استخدام العامل && يضمن عدم محاولة عرض البيانات قبل وصولها، وهي ممارسة شائعة وآمنة في React.

أفضل ممارسات عند استخدام React Hooks

  • استخدم Hooks فقط داخل functional components أو داخل Custom Hooks.
  • لا تستدعِ Hooks داخل الشروط أو الحلقات التكرارية.
  • احرص على تسمية Custom Hooks بصيغة تبدأ بـ use.
  • حدّد dependency array بعناية لتجنّب التحديثات غير المتوقعة.
  • قسّم المنطق المتكرر إلى Hooks مستقلة لتحسين بنية المشروع.

مقارنة سريعة بين useState و useEffect

Hook الوظيفة متى يُستخدم؟
useState إدارة البيانات القابلة للتغيير داخل المكون عند التعامل مع قيم مثل النصوص والأرقام والحقول
useEffect تنفيذ التأثيرات الجانبية بعد الـ render عند جلب البيانات أو مراقبة تغيّر القيم أو التعامل مع DOM

الخلاصة التقنية

تُعد React Hooks من أهم الأدوات التي جعلت كتابة functional components أكثر قوة وتنظيماً. يمنحك useState طريقة مباشرة لإدارة الحالة، بينما يوفّر useEffect آلية مرنة للتعامل مع التأثيرات الجانبية ومراقبة التغييرات. أما Custom Hooks فهي خطوة متقدمة تساعدك على بناء شيفرة قابلة لإعادة الاستخدام وأكثر احترافية. إذا كنت تطور تطبيقات React حديثة، فإن إتقان هذه المفاهيم ليس خياراً إضافياً، بل مهارة أساسية لتحسين جودة الكود وسهولة صيانته على المدى الطويل.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *