شرح Context API في React من الصفر بالعربي

هذا الدرس هو شرح Context API في React من الصفر بالعربي بأسلوب بسيط، هدفه حل أكبر مشكلة تواجه المبتدئين: prop drilling. تخيّل أنك تمرر نفس البيانات عبر 5 مكوّنات فقط لكي تصل لمكوّن واحد — هذا هو سبب وجود Context API.

لماذا Context API لإدارة الحالة العالمية في React؟

  • تتجنب تمرير البيانات عبر props في كل مستوى.
  • تشارك بيانات مثل المستخدم الحالي أو الثيم بسهولة.
  • حل مدمج في React بدون مكتبات إضافية.

المشكلة: Prop Drilling

Prop drilling يعني أنك تمرر نفس البيانات من الأب إلى الابن، ثم حفيد، ثم حفيد الحفيد… حتى تصل للمكوّن المطلوب. هذا يجعل الكود طويل وصعب الصيانة.

الحل: Context API خطوة بخطوة

import { createContext } from "react";

export const UserContext = createContext(null);

شرح مفصل خطوة بخطوة:

  • استوردنا createContext من React لأنه المسؤول عن إنشاء الـ Context.
  • أنشأنا UserContext كقناة بيانات مشتركة بين المكوّنات.
  • أعطيناه قيمة افتراضية null، حتى نضع القيمة الفعلية داخل Provider لاحقًا.

استخدام Provider لتوزيع البيانات

import { UserContext } from "./UserContext";

function App() {
  const user = { name: "Ahmed", role: "Admin" };

  return (
    <UserContext.Provider value={user}>
      <Dashboard />
    </UserContext.Provider>
  );
}

شرح مفصل خطوة بخطوة:

  • عرّفنا كائن المستخدم داخل App.
  • لفّينا واجهة التطبيق بـ UserContext.Provider.
  • مرّرنا بيانات المستخدم داخل value.
  • أي مكوّن داخل الـ Provider سيحصل على نفس البيانات بدون تمرير props.

الوصول للبيانات باستخدام useContext

import { useContext } from "react";
import { UserContext } from "./UserContext";

function Profile() {
  const user = useContext(UserContext);

  return <h2>مرحبًا {user.name}</h2>;
}

شرح مفصل خطوة بخطوة:

  • استوردنا useContext لأنها تقرأ القيمة من الـ Context مباشرة.
  • أعطيناها UserContext فترجع قيمة المستخدم.
  • الآن نستعمل user.name بدون أي props أو تمرير يدوي.

مثال عملي: ثيم (Theme) عالمي

import { createContext, useContext, useState } from "react";

const ThemeContext = createContext("light");

function App() {
  const [theme, setTheme] = useState("light");

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  return <ThemeButton />;
}

function ThemeButton() {
  const { theme, setTheme } = useContext(ThemeContext);
  return (
    <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
      الوضع الحالي: {theme}
    </button>
  );
}

شرح مفصل خطوة بخطوة:

  • أنشأنا ThemeContext بقيمة افتراضية light.
  • داخل App خزّنا الثيم في state عبر useState.
  • مرّرنا theme و setTheme داخل Provider.
  • المكوّن Toolbar لا يحتاج أي props لكنه يمرر التحكم للأزرار.
  • ThemeButton يقرأ theme ويغيّره عند الضغط.

أفضل طريقة: Custom Hook لتبسيط الاستخدام

import { useContext } from "react";
import { UserContext } from "./UserContext";

export function useUser() {
  const user = useContext(UserContext);
  if (!user) throw new Error("useUser must be used within UserProvider");
  return user;
}

هذا يجعل الكود أنظف ويمنع استخدام Context خارج Provider.

متى يكون Context API غير كافٍ؟

  • عندما تصبح البيانات كثيرة ومعقدة جدًا.
  • عندما تحتاج أدوات تتبع وتدقيق (DevTools) قوية.
  • عندما تحتاج إدارة متقدمة مثل Redux Toolkit أو Zustand.

تحسين الأداء في Context API

أي تغيير في value يعيد رندر كل المستهلكين. لتجنب إعادة رندر غير ضرورية:

import { useMemo } from "react";

const value = useMemo(() => ({ user, setUser }), [user]);

<UserContext.Provider value={value}>
  <App />
</UserContext.Provider>

شرح مفصل خطوة بخطوة:

  • لو أنشأنا كائن جديد في كل رندر، كل المستهلكين سيعيدون الرندر.
  • useMemo يثبت قيمة value طالما لم يتغير user.
  • النتيجة: أداء أفضل وتقليل إعادة الرندر غير الضرورية.

بهذه الطريقة تقل عمليات الرندر، وتبقى تجربة التطبيق أسرع.

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

ما هو Context API في React؟

طريقة لمشاركة البيانات بين المكوّنات بدون تمرير props في كل مستوى.

متى أستخدم Context API؟

عندما تحتاج بيانات مشتركة مثل المستخدم الحالي أو الثيم.

هل Context API بديل عن Redux؟

ليس دائمًا، لكنه مناسب للحالات البسيطة والمتوسطة.

ما هو prop drilling؟

تمرير البيانات عبر مستويات كثيرة حتى تصل للمكوّن المطلوب.

كيف أحسن أداء Context API؟

قسّم السياقات وثبّت قيمة Provider بـ useMemo.

التالي: سننتقل لدرس Redux Toolkit لإدارة الحالة بشكل أوسع.
المحرر الذكي

اكتب الكود وشاهد النتيجة فوراً

جرب الآن مجاناً
قناة ديف عربي

تابع أحدث الدروس والتحديثات مباشرة على واتساب

انضم الآن