تخطَّ إلى المحتوى

⚛️ شرح React

سياق React (useContext)

الدرس 13 من 32· ⏱ 3 دقائق قراءة· 🗓 آخر تحديث: ١٧ يوليو ٢٠٢٦

المشكلة: تمرير الخصائص العميق (Prop Drilling)

حين تحتاج بيانات (مثل المستخدم أو الثيم) في مكوّنات عميقة، تمرّرها عبر props خلال كل مستوى — حتى المكوّنات التي لا تحتاجها. هذا مرهق. الحلّ: Context.

ثلاث خطوات لاستخدام Context

1) إنشاء السياق

import { createContext } from "react";

export const ThemeContext = createContext();

2) التزويد بالقيمة (Provider)

غلّف الجزء الذي يحتاج البيانات:

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

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

3) الاستهلاك بـ useContext

أي مكوّن داخل الـ Provider يصل للقيمة مباشرةً:

import { useContext } from "react";

function ThemeButton() {
  const { theme, setTheme } = useContext(ThemeContext);

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

لا حاجة لتمرير theme عبر كل المستويات!

مثال متكامل: سياق المستخدم

const UserContext = createContext();

function App() {
  const [user, setUser] = useState({ name: "براء" });
  return (
    <UserContext.Provider value={user}>
      <Navbar />
    </UserContext.Provider>
  );
}

function Navbar() {
  const user = useContext(UserContext);
  return <p>أهلًا {user.name}</p>;
}

متى تستخدم Context؟

مثالي للبيانات العامّة التي يحتاجها كثيرون: الثيم، المستخدم المسجَّل، اللغة، سلة التسوّق.

⚠️ ليس بديلًا عن كل props. للبيانات المحلّية بين مكوّنين، يبقى تمرير props أبسط. وللحالة المعقّدة الضخمة، فكّر في مكتبات إدارة الحالة (Redux, Zustand).

نمط متقدم: Context + Repository

عندما يحتاج الـ Context إلى جلب بيانات (مثل المستخدم الحالي)، لا تضع fetch داخل الـ Provider مباشرة. استخدم Repository Pattern:

import { createContext, useContext, useState, ReactNode } from "react";
import { HttpClient, UserRepository, HttpUserRepository, ApiError, NetworkError } from "./lib/react-base-repository";

// Repository — الطبقة الوحيدة التي تتصل بالخادم
const http = new HttpClient("/api");
const authRepo: UserRepository = new HttpUserRepository(http);

// Service Interface
interface AuthContextType {
  user: UserDTO | null;
  login(email: string, password: string): Promise<void>;
  logout(): void;
}

const AuthContext = createContext<AuthContextType | null>(null);

// Provider — يستخدم Repository، لا يستدعي fetch مباشرة
function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<UserDTO | null>(null);

  async function login(email: string, password: string) {
    try {
      const loggedInUser = await authRepo.createUser({ name: email, email, isActive: true });
      setUser(loggedInUser);
    } catch (err) {
      if (err instanceof ApiError) throw new Error(err.message);
      if (err instanceof NetworkError) throw new Error("تعذّر الاتصال");
      throw err;
    }
  }

  function logout() { setUser(null); }

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

// Custom Hook — Service Layer (المكوّنات تستخدم هذا فقط)
function useAuth(): AuthContextType {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth must be used within AuthProvider");
  return ctx;
}

// المكوّن — لا يعرف Repository أو HTTP
function LoginButton() {
  const { login } = useAuth();
  return <button onClick={() => login("a@b.com", "pw").catch(alert)}>دخول</button>;
}

الأخطاء الشائعة

  • ❌ وضع كل شيء في Context → يصعّب التتبّع ويُعيد عرض الكثير.
  • ❌ استهلاك السياق خارج الـ Provider → القيمة تكون افتراضية/غير معرّفة.
  • ❌ قيمة كائن جديدة في كل عرض → قد تسبّب إعادة عرض زائدة (استخدم useMemo عند الحاجة).

خلاصة

Context يشارك البيانات العامّة دون prop drilling: أنشئ بـ createContext، زوّد بـ .Provider value={...}، واستهلك بـ useContext. مثالي للثيم والمستخدم واللغة — حلٌّ أنيق لمشكلة تمرير الخصائص العميق.

شرح سياق React (useContext) — React بالعربي
سياق React (useContext)React بالعربي · The Code Fix

📚 لمزيد من التعمّق في React، راجِع التوثيق الرسمي لـ React.

هل كان هذا الدرس مفيدًا؟