المكوّنات متعددة الأشكال باستخدام خاصية 'as'
حدّد نوع خاصية 'as' بحيث يصيّر Button كـ أو مع الحفاظ على أنواع الخصائص الصحيحة.
المكوّنات متعددة الأشكال باستخدام خاصية 'as' درس مجاني في React Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في React Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة React Academy 4 دروس في المجموع.
ما المكوّن متعدد الأشكال؟
يعرض المكوّن متعدد الأشكال عناصر HTML أو مكونات مختلفة بناءً على خاصية as — مثل Button الذي يُعرض كعنصر <a> أو <button> مع الحفاظ على أنواع TypeScript الصحيحة.
خاصية as البسيطة (من دون TypeScript)
تنفيذ أساسي متعدد الأشكال من دون الأنواع العامة — يفقد أمان الأنواع، لكنه يوضح المفهوم.
function Box({ as: Tag = 'div', children, ...props }) {
return <Tag {...props}>{children}</Tag>;
}
// Usage:
<Box as="section" className="hero">...</Box>
<Box as="article">...</Box>خاصية as مقيّدة بالأنواع مع الأنواع العامة
أضف معلمة نوع عامة لاستنتاج الخصائص الصحيحة لأي عنصر تُظهره as.
type PolymorphicProps<E extends React.ElementType> = {
as?: E;
} & Omit<React.ComponentPropsWithoutRef<E>, 'as'>;
function Box<E extends React.ElementType = 'div'>({
as,
...props
}: PolymorphicProps<E>) {
const Tag = as ?? 'div';
return <Tag {...props} />;
}دعم ref
أضف دعم forwardRef مع الحفاظ على الكتابة متعددة الأشكال.
type PolymorphicRef<E extends React.ElementType> = React.ComponentPropsWithRef<E>['ref'];
type PolymorphicPropsWithRef<E extends React.ElementType, P = {}> = P &
Omit<React.ComponentPropsWithRef<E>, keyof P> & { as?: E };
const Button = React.forwardRef(
<E extends React.ElementType = 'button'>(
{ as, ...props }: PolymorphicPropsWithRef<E>,
ref: PolymorphicRef<E>
) => {
const Tag = as ?? 'button';
return <Tag ref={ref} {...props} />;
}
);استنتاج TypeScript عمليًا
عند ضبط as='a'، يعرف TypeScript أن المكوّن يقبل خصائص خاصة بالروابط مثل href وtarget، لكنه لا يقبل الخصائص الخاصة بالأزرار مثل disabled.
// TypeScript allows href because as='a':
<Box as="a" href="https://example.com">Link</Box>
// TypeScript errors if you pass href to a div:
<Box as="div" href="...">Error!</Box> // TS: href is not a valid div propالتوسعة بخصائص مخصصة
أضف خصائص خاصة بالمكوّن إلى جانب الأساس متعدد الأشكال، من خلال تضمينها في تعريف النوع.
type TextProps<E extends React.ElementType> = PolymorphicProps<E> & {
size?: 'sm' | 'md' | 'lg';
weight?: 'normal' | 'bold';
};
function Text<E extends React.ElementType = 'p'>({
as,
size = 'md',
weight = 'normal',
className,
...props
}: TextProps<E>) {
const Tag = as ?? 'p';
return (
<Tag
className={[`text-${size}`, `font-${weight}`, className].filter(Boolean).join(' ')}
{...props}
/>
);
}حالة استخدام عملية: رابط يُعرض كـ RouterLink
مكوّن Button يُعرض كرابط React Router عند توفير to، أو كزر عادي خلاف ذلك.
import { Link } from 'react-router-dom';
type ButtonProps =
| { to: string; href?: never } & React.ComponentPropsWithoutRef<typeof Link>
| { href: string; to?: never } & React.ComponentPropsWithoutRef<'a'>
| { to?: never; href?: never } & React.ComponentPropsWithoutRef<'button'>;
function Button({ to, href, ...props }: ButtonProps) {
if (to) return <Link to={to} {...props} />;
if (href) return <a href={href} {...props} />;
return <button type="button" {...props} />;
}مكوّن Text لنظام التصميم
مكوّن Text متعدد الأشكال يُعرض افتراضيًا كعنصر <p>، لكن يمكن عرضه كعنصر h1–h6 أو span أو label.
<Text as="h1" size="xl">Page Title</Text>
<Text as="span" weight="bold">Inline bold</Text>
<Text as="label" htmlFor="email">Email</Text> // htmlFor is valid because as='label'قيود على خاصية as
استخدم extends React.ElementType لقبول سلاسل عناصر HTML ('div' و'a') ومكونات React معًا.
function Card<E extends React.ElementType = 'div'>({ as, ...props }: PolymorphicProps<E>) {
const Tag = as ?? 'div';
return <Tag {...props} />;
}
// Works with HTML elements:
<Card as="section" aria-label="Products" />
// Works with React components:
<Card as={motion.div} animate={{ opacity: 1 }} />تجنب الأخطاء الشائعة
لا تمرّر خاصية as إلى العنصر عند نشر الخصائص (فهي ليست سمة HTML صالحة). أزلها دائمًا بالتفكيك قبل نشر بقية الخصائص.
// Bad:
function Box({ as: Tag = 'div', ...props }) {
return <Tag as={...} {...props} />; // 'as' attribute on div is invalid HTML
}
// Good:
function Box({ as: Tag = 'div', ...props }) {
return <Tag {...props} />; // 'as' is used to pick Tag, not passed to element
}اعتبارات الأداء
تضيف المكونات متعددة الأشكال تكلفة ضئيلة جدًا على الأداء — فخاصية as ليست سوى متغير يحتفظ بسلسلة نوع عنصر أو مرجع مكوّن.
تحقق سريع
لماذا ينبغي تفكيك خاصية as قبل نشر بقية الخصائص إلى العنصر في مكوّن متعدد الأشكال؟
مراجعة
تستخدم المكونات متعددة الأشكال خاصية عامة as?: E extends React.ElementType لعرض أي عنصر مع الحفاظ على خصائص TypeScript الصحيحة. فكّك as قبل نشر بقية الخصائص. استخدم React.ComponentPropsWithoutRef لتضمين جميع السمات الخاصة بالعنصر في النوع.
الأسئلة الشائعة
هل درس «المكوّنات متعددة الأشكال باستخدام خاصية 'as'» مجاني؟
نعم — نص درس «المكوّنات متعددة الأشكال باستخدام خاصية 'as'» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة React Academy، انتقل إلى CoddyKit PRO. تتضمن دورة React Academy 4 دروس في المجموع.
ماذا ستتعلم في «المكوّنات متعددة الأشكال باستخدام خاصية 'as'»؟
حدّد نوع خاصية 'as' بحيث يصيّر Button كـ أو مع الحفاظ على أنواع الخصائص الصحيحة. تتمرن على React Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ React Academy؟
لا تُشترط خبرة سابقة. React Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «المكوّنات متعددة الأشكال باستخدام خاصية 'as'»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس React Academy هذا؟
نعم. كل درس في React Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- الاتحادات المميّزة لأشكال المكوّنات
- الأنواع الشرطية والمُعيّنة في React
- المكوّنات متعددة الأشكال باستخدام خاصية 'as'
- النماذج الآمنة نوعيًا وعقود استجابات API