الدرس الثامن والعشرون: استخدام Context API و Hooks معًا في React
في React، تُعتبر Context API أداة قوية لتمرير البيانات بين المكونات دون الحاجة إلى استخدام الـ props بشكل مفرط. بالإضافة إلى ذلك، يمكن دمجها مع Hooks مثل useState و useReducer لإدارة الحالة في تطبيقات React الكبيرة والمتعددة المكونات. في هذا الدرس، سوف نتعلم كيفية دمج Context API مع useState و useReducer لإدارة الحالة عبر التطبيق، وكيفية استخدام useContext للحصول على البيانات من الـ context.
1. مقدمة إلى Context API
Context API هو نظام في React يسمح بتمرير البيانات عبر شجرة المكونات دون الحاجة إلى تمرير البيانات يدوياً عبر الـ props لكل مكون على حدة. يسمح لك ذلك بحل مشكلة “التصعيد” (prop drilling)، وهي الحالة التي يتم فيها تمرير البيانات من مكون أب إلى مكونات كثيرة أخرى.
متى نستخدم Context API؟
- عندما تحتاج إلى تمرير بيانات أو حالة معينة إلى العديد من المكونات على مستويات متعددة.
- عندما تحتاج إلى تخزين البيانات المشتركة بين المكونات (مثل المستخدم المسجل، اللغة المفضلة، إعدادات التطبيق، إلخ).
2. دمج Context API مع useState
عندما نحتاج إلى تخزين حالة بسيطة في Context، يمكننا دمج useState مع Context لإدارة البيانات التي تتغير بمرور الوقت.
إنشاء Context وتوفير البيانات باستخدام useState:
import React, { createContext, useState } from 'react';
// إنشاء Context
const ThemeContext = createContext<any>(null);
const ThemeProvider: React.FC = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((prevTheme: string) => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
export { ThemeProvider, ThemeContext };
استخدام الـ Context في مكون آخر:
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeProvider';
const ThemeSwitcher: React.FC = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div>
<p>Current theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
};
export default ThemeSwitcher;
في هذا المثال:
- أنشأنا ThemeContext الذي يحمل حالة theme (إما “light” أو “dark”).
- استخدمنا useState داخل ThemeProvider لتخزين قيمة theme وتوفير دالة toggleTheme لتغيير هذه القيمة.
- في المكون ThemeSwitcher، استخدمنا useContext للوصول إلى قيمة theme ودالة toggleTheme من الـ context.
3. دمج Context API مع useReducer
عند الحاجة إلى إدارة حالة أكثر تعقيدًا، مثل حالة تحتوي على عدة خصائص أو تتطلب منطقًا معقدًا، يمكننا دمج Context API مع useReducer لإدارة الحالة.
إنشاء Reducer مع Context:
import React, { createContext, useReducer } from 'react';
// إنشاء Context
const CounterContext = createContext<any>(null);
// تعريف Actions
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
// تعريف الـ Reducer
const counterReducer = (state: any, action: any) => {
switch (action.type) {
case INCREMENT:
return { ...state, count: state.count + 1 };
case DECREMENT:
return { ...state, count: state.count - 1 };
default:
return state;
}
};
// إنشاء Provider
const CounterProvider: React.FC = ({ children }) => {
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
return (
<CounterContext.Provider value={{ state, dispatch }}>
{children}
</CounterContext.Provider>
);
};
export { CounterProvider, CounterContext, INCREMENT, DECREMENT };
استخدام الـ Context مع useReducer في مكون آخر:
import React, { useContext } from 'react';
import { CounterContext, INCREMENT, DECREMENT } from './CounterProvider';
const Counter: React.FC = () => {
const { state, dispatch } = useContext(CounterContext);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: INCREMENT })}>Increment</button>
<button onClick={() => dispatch({ type: DECREMENT })}>Decrement</button>
</div>
);
};
export default Counter;
في هذا المثال:
- استخدمنا useReducer لإدارة حالة أكثر تعقيدًا، حيث أن الحالة تحتوي على عدد (count) الذي يمكن زيادته أو تقليله باستخدام إجراءات INCREMENT و DECREMENT.
- أنشأنا CounterContext لتوفير الحالة ودالة التحديث للمكونات الأخرى.
- في مكون Counter، استخدمنا useContext للوصول إلى state و dispatch من الـ context واستخدامها لتحديث الحالة.
4. إدارة الحالة عبر التطبيق باستخدام Context
من خلال Context API و Hooks، يمكننا مشاركة حالة عبر جميع المكونات في التطبيق بسهولة. على سبيل المثال، إذا كنت تستخدم useState أو useReducer داخل Context، يمكن لجميع المكونات الوصول إلى هذه الحالة دون الحاجة إلى تمريرها عبر الـ props.
مثال لتطبيق شجرة المكونات:
- App: يحتوي على ThemeProvider و CounterProvider.
- ThemeSwitcher: مكون يستخدم Context لتبديل السمة بين “light” و “dark”.
- Counter: مكون يعرض العدادات ويوفر أزرار لزيادة أو تقليل القيمة.
import React from 'react';
import { ThemeProvider } from './ThemeProvider';
import { CounterProvider } from './CounterProvider';
import ThemeSwitcher from './ThemeSwitcher';
import Counter from './Counter';
const App: React.FC = () => {
return (
<ThemeProvider>
<CounterProvider>
<div>
<ThemeSwitcher />
<Counter />
</div>
</CounterProvider>
</ThemeProvider>
);
};
export default App;
5. استخدام useContext للحصول على البيانات من الـ Context
useContext هو الـ Hook الذي يمكنك من الوصول إلى البيانات المخزنة في الـ context. يُعد هذا أسلوبًا بسيطًا ومباشرًا لاستخدام البيانات التي تم توفيرها عبر Context.
مثال عملي:
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeProvider';
const CurrentTheme: React.FC = () => {
const { theme } = useContext(ThemeContext);
return <p>The current theme is {theme}</p>;
};
export default CurrentTheme;
في هذا المثال، استخدمنا useContext للحصول على theme من ThemeContext وعرضه في المكون.
6. الملخص
في هذا الدرس، تعلمنا كيفية دمج Context API مع useState و useReducer لإدارة الحالة في تطبيق React. قمنا بإنشاء Contexts لإدارة البيانات مثل السمة (theme) وعدد المستخدمين (counter)، وناقشنا كيفية استخدام useContext لاستخراج البيانات من Context داخل المكونات. باستخدام هذه الأدوات معًا، يمكننا بناء تطبيقات React أكثر تنظيمًا وقوة.
اكتشاف المزيد من كود التطور
اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.


