المكوّنات المركّبة باستخدام Context
شارك الحالة الضمنية بين مكوّن أبن ومكوّناته الأبناء المحددة باستخدام Context، ونمذج واجهات برمجية مثل و
المكوّنات المركّبة باستخدام Context درس مجاني في Frontend Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Frontend Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Frontend Academy 4 دروس في المجموع.
ما المكوّنات المركّبة؟
المكوّنات المركّبة هي مجموعة من المكوّنات المرتبطة المصممة للعمل معًا كوحدة واحدة، مثل <select> و<option> في HTML. يشارك المكوّن الأب الحالة ضمنيًا مع أبنائه المحددين.
الهدف: واجهات API أنظف
بدلًا من <Select options={[...]} value={x} onChange={...} />، تكتب <Select><Option value="a">Apple</Option></Select>. تكون البنية تصريحية وطبيعية في JSX.
النهج الساذج (المشكلة)
يتطلب تمرير الحالة عبر الخصائص من المستهلك توصيل كل شيء يدويًا. لا يعرف الأبناء حالة الأب تلقائيًا.
// Without compound pattern — verbose:
<Tabs activeIndex={0} onChange={setIndex}>
<TabList>
<Tab index={0}>Home</Tab>
<Tab index={1}>Profile</Tab>
</TabList>
</Tabs>Context بوصفه حلقة الوصل
ينشئ الأب Context بالحالة المشتركة ويوفرها. ويستهلك الأبناء هذا السياق، من دون توصيل صريح للخصائص.
import { createContext, useContext, useState } from 'react';
const TabsContext = createContext(null);
export function Tabs({ children, defaultIndex = 0 }) {
const [activeIndex, setActiveIndex] = useState(defaultIndex);
return (
<TabsContext.Provider value={{ activeIndex, setActiveIndex }}>
<div className="tabs">{children}</div>
</TabsContext.Provider>
);
}تستهلك المكوّنات الابنة السياق
تقرأ كل مكوّنة ابنة من السياق، من دون تمرير الخصائص عبر شجرة المكوّنات.
export function Tab({ index, children }) {
const { activeIndex, setActiveIndex } = useContext(TabsContext);
const isActive = activeIndex === index;
return (
<button
className={isActive ? 'active' : ''}
onClick={() => setActiveIndex(index)}
>
{children}
</button>
);
}
export function Panel({ index, children }) {
const { activeIndex } = useContext(TabsContext);
if (activeIndex !== index) return null;
return <div className="panel">{children}</div>;
}الخصائص الثابتة لتسهيل الاكتشاف
أرفق المكوّنات الفرعية بالأب، حتى يتمكن المستخدمون من اكتشافها عبر الإكمال التلقائي.
Tabs.Tab = Tab;
Tabs.Panel = Panel;
// Usage:
<Tabs>
<Tabs.Tab index={0}>Home</Tabs.Tab>
<Tabs.Tab index={1}>Profile</Tabs.Tab>
<Tabs.Panel index={0}>Home content</Tabs.Panel>
<Tabs.Panel index={1}>Profile content</Tabs.Panel>
</Tabs>مثال واقعي: Disclosure
تحتوي أداة Disclosure على ابنين هما Trigger وPanel، ويتشاركان حالة الفتح والإغلاق عبر السياق.
function Disclosure({ children }) {
const [isOpen, setIsOpen] = useState(false);
return (
<DisclosureContext.Provider value={{ isOpen, setIsOpen }}>
<div>{children}</div>
</DisclosureContext.Provider>
);
}
function Trigger({ children }) {
const { isOpen, setIsOpen } = useContext(DisclosureContext);
return <button onClick={() => setIsOpen(o => !o)}>{children}</button>;
}
function Panel({ children }) {
const { isOpen } = useContext(DisclosureContext);
return isOpen ? <div>{children}</div> : null;
}Hooks بوصفها واجهة API العامة
صدّر Hook مخصّصة حتى يتمكن المستخدمون من بناء مكوّناتهم الخاصة فوق مكوّناتك.
export function useTabs() {
const ctx = useContext(TabsContext);
if (!ctx) throw new Error('useTabs must be used inside <Tabs>');
return ctx;
}المكوّنات المركّبة متعددة الأشكال
اسمح للآباء بتصيير أي عنصر عبر خاصية as أو نمط asChild (وهو نهج Radix UI). يتيح ذلك للمكوّنات المركّبة التركيب مع JSX عشوائي.
أنماط المكوّنات المركّبة غير المرئية
توفر المكتبات غير المرئية (Radix وHeadless UI) مكوّنات مركّبة بلا تنسيق، مع تضمين منطق إمكانية الوصول، بينما تتولى أنت تنسيقها حسب الحاجة.
مشكلة شائعة: فحص الأبناء
كان أحد الأنماط القديمة يستخدم React.Children لفحص الأبناء، لكنه هش وسهل الانكسار. فضّل السياق دائمًا لمشاركة الحالة.
اختبار سريع
في نمط المكوّنات المركّبة، كيف تتواصل المكوّنات الابنة مع المكوّن الأب؟
مراجعة: المكوّنات المركّبة
تتيح المكوّنات المركّبة للأجزاء المرتبطة العمل كوحدة تصريحية واحدة. استخدم Context لمشاركة الحالة، مع Provider في الأب وuseContext في الأبناء. أرفق المكوّنات الفرعية كخصائص ثابتة لتسهيل اكتشافها. صدّر Hook مخصّصة بوصفها واجهة API العامة. يُعد Radix وHeadless UI مرجعين ممتازين. فضّل السياق على فحص Children.
الأسئلة الشائعة
هل درس «المكوّنات المركّبة باستخدام Context» مجاني؟
نعم — نص درس «المكوّنات المركّبة باستخدام Context» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Frontend Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Frontend Academy 4 دروس في المجموع.
ماذا ستتعلم في «المكوّنات المركّبة باستخدام Context»؟
شارك الحالة الضمنية بين مكوّن أبن ومكوّناته الأبناء المحددة باستخدام Context، ونمذج واجهات برمجية مثل و تتمرن على Frontend Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Frontend Academy؟
لا تُشترط خبرة سابقة. Frontend Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «المكوّنات المركّبة باستخدام Context»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Frontend Academy هذا؟
نعم. كل درس في Frontend Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- المكوّنات المركّبة باستخدام Context
- أنماط Render Props وHOC
- Portals للنوافذ المنبثقة والتلميحات
- حدود الأخطاء