Context API

🎯 ما هي Context API ؟

Context API هي طريقة في React لتمرير البيانات بين المكونات بدون الحاجة لتمرير props يدويًا عبر كل المستويات.

يعني بدل ما تعمل:

<App>
  <Parent>
    <Child>
      <GrandChild name="Ahmad" /> {/* تمرير عبر عدة طبقات */}
    </Child>
  </Parent>
</App>
JSX

تقدر تستخدم context وتخلي كل المكونات تشوف نفس القيمة مباشرة، بدون تمرير props يدويًا.
🧠 فكر فيها مثل مخزن صغير داخل التطبيق يمكن لأي مكون الوصول إليه.

🧩 متى نحتاجها؟
  • لما عندك بيانات أو حالة يحتاجها أكثر من مكون في أماكن بعيدة عن بعضها.
  • أمثلة شائعة:
    • لغة الموقع (عربي/إنجليزي)
    • وضع الإضاءة (فاتح/داكن)
    • المستخدم المسجّل حاليًا
    • سلة التسوق
    • إعدادات عامة للتطبيق
⚙️ طريقة الاستخدام
  1. إنشاء الـ Context
  2. تغليف المكونات بـ Provider
  3. استهلاك البيانات بـ useContext
مثال عملي بسيط 👇

🔹 1. إنشاء Context

import { createContext, useState } from "react";

export const ThemeContext = createContext(); // الخطوة الأولى

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");

  const toggleTheme = () =>
    setTheme((prev) => (prev === "light" ? "dark" : "light"));

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}
JSX
🔹 2. تغليف التطبيق بـ Provider (عادة في main.jsx أو App.jsx)
import ReactDOM from "react-dom/client";
import App from "./App";
import { ThemeProvider } from "./ThemeContext";

ReactDOM.createRoot(document.getElementById("root")).render(
  <ThemeProvider>
    <App />
  </ThemeProvider>
);
JSX
🔹 3. استهلاك القيم داخل مكون (باستخدام useContext)
import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

export default function Child() {
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <div
      style={{
        background: theme === "light" ? "#fff" : "#333",
        color: theme === "light" ? "#000" : "#fff",
        padding: 20,
        textAlign: "center",
      }}
    >
      <p>الوضع الحالي: {theme}</p>
      <button onClick={toggleTheme}>تبديل الوضع</button>
    </div>
  );
}
JSX
💡 النتيجة:

كل مكون داخل <ThemeProvider> يقدر يقرأ أو يغيّر theme بدون تمريرها كـ prop.
حتى لو كان مكون “حفيد” بعيد جدًا!

🔥 ملاحظات مهمة:
  • القيم اللي داخل الـ context تُخزَّن في الذاكرة (state).
  • كل مرة تتغيّر فيها القيمة داخل الـ Providerيُعاد رندر كل المكونات اللي تستخدمها.
  • استخدمها للقيم العامة فقط، مو لكل شيء! (لا تكثرها بدون داعٍ).
  • أحيانًا يُفضل مكتبات إدارة الحالة (مثل Redux أو Zustand) لو التطبيق كبير جدًا.
📦 مثال كامل صغير:
// ThemeContext.js
import { createContext, useState } from "react";
export const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState("light");
  const toggle = () => setTheme(t => (t === "light" ? "dark" : "light"));
  return (
    <ThemeContext.Provider value={{ theme, toggle }}>
      {children}
    </ThemeContext.Provider>
  );
};
JSX
// App.jsx
import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

export default function App() {
  const { theme, toggle } = useContext(ThemeContext);

  return (
    <div style={{
      background: theme === "light" ? "#fff" : "#222",
      color: theme === "light" ? "#000" : "#fff",
      height: "100vh",
      textAlign: "center",
      paddingTop: 50
    }}>
      <h1>الوضع الحالي: {theme}</h1>
      <button onClick={toggle}>بدّل الوضع</button>
    </div>
  );
}
JSX
// main.jsx
import { createRoot } from "react-dom/client";
import { ThemeProvider } from "./ThemeContext";
import App from "./App";

createRoot(document.getElementById("root")).render(
  <ThemeProvider>
    <App />
  </ThemeProvider>
);
JSX
🧠 ملخّص سريع:
الخطوةالوظيفة
createContext()إنشاء السياق
<Context.Provider>تمرير القيم إلى الشجرة
useContext(Context)قراءة القيم داخل أي مكون
Providerيغلّف المكونات التي تحتاج الوصول للسياق
🍉 أولًا: ليش ممكن تحتاج أكثر من Context؟

أحيانًا التطبيق فيه أكثر من نوع بيانات عام لازم يتشارك بين المكونات:
مثلاً:

  • ThemeContext → لإدارة الوضع الليلي والفاتح
  • AuthContext → لتخزين المستخدم المسجّل
  • LanguageContext → للغة الموقع
  • CartContext → لسلة التسوّق

لو جمعت كل هالبيانات في Context واحد، بصير ضخم ومعقّد.
فالأفضل تفصلهم كل واحد في ملفه.

🍉🍈 مثال عملي: Theme + Auth Context
1️⃣ إنشاء ThemeContext
// ThemeContext.js
import { createContext, useState } from "react";

export const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState("light");
  const toggleTheme = () =>
    setTheme((prev) => (prev === "light" ? "dark" : "light"));

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};
JSX
2️⃣ إنشاء AuthContext
// AuthContext.js
import { createContext, useState } from "react";

export const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);

  const login = (name) => setUser({ name });
  const logout = () => setUser(null);

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};
JSX
3️⃣ تغليفهم معًا

في main.jsx أو ملف مركزي خاص بـ “اللفّاف” (Wrapper):

import ReactDOM from "react-dom/client";
import App from "./App";
import { ThemeProvider } from "./ThemeContext";
import { AuthProvider } from "./AuthContext";

ReactDOM.createRoot(document.getElementById("root")).render(
  <ThemeProvider>
    <AuthProvider>
      <App />
    </AuthProvider>
  </ThemeProvider>
);
JSX

💡 الترتيب مهم فقط لو أحد الـ Contexts يعتمد على الآخر.
(مثلاً لو AuthContext يعتمد على theme، لازم يجي داخله.)

4️⃣ استخدام أكثر من Context داخل نفس المكون
import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";
import { AuthContext } from "./AuthContext";

export default function Profile() {
  const { theme, toggleTheme } = useContext(ThemeContext);
  const { user, login, logout } = useContext(AuthContext);

  return (
    <div
      style={{
        background: theme === "light" ? "#fff" : "#333",
        color: theme === "light" ? "#000" : "#fff",
        padding: 20,
        textAlign: "center",
      }}
    >
      <h2>الوضع الحالي: {theme}</h2>
      <button onClick={toggleTheme}>بدّل اللون</button>

      <hr />

      {user ? (
        <>
          <p>مرحباً يا {user.name} 👋</p>
          <button onClick={logout}>تسجيل الخروج</button>
        </>
      ) : (
        <button onClick={() => login("أحمد")}>تسجيل الدخول</button>
      )}
    </div>
  );
}
JSX
🧠 نصيحة احترافية:

لو زادت كثير وصار عندك أكثر من 3–4 Contexts،
اعمل ملف اسمه مثلاً AppProviders.jsx لتجمعهم بسهولة:

// AppProviders.jsx
import { ThemeProvider } from "./ThemeContext";
import { AuthProvider } from "./AuthContext";

export const AppProviders = ({ children }) => (
  <ThemeProvider>
    <AuthProvider>{children}</AuthProvider>
  </ThemeProvider>
);
JSX

ثم في main.jsx:

import { AppProviders } from "./AppProviders";

createRoot(document.getElementById("root")).render(
  <AppProviders>
    <App />
  </AppProviders>
);
JSX
🧩 ملخّص سريع:
الحالةالحل
عندك بيانات عامة كثيرةافصلها في أكثر من Context
تحتاج الوصول لأكثر من واحدةاستخدم useContext لكل واحدة
عندك Contexts كثيرةلفها بـ AppProviders لتبسيط الكود