0Pricing
React Academy · บทเรียน

คอมโพเนนต์พหุรูปแบบด้วย Prop 'as'

กำหนดชนิดของ prop 'as' เพื่อให้ Button แสดงผลเป็น หรือ พร้อมคงชนิด prop ที่ถูกต้อง

คอมโพเนนต์พหุรูปแบบด้วย Prop 'as' เป็นบทเรียน React Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 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} />;
}

การรองรับการอ้างอิง

เพิ่มการรองรับ 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 ที่เรนเดอร์เป็นลิงก์ของเราเตอร์รีแอ็กต์เมื่อมีการระบุ 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 แบบพหุรูปแบบ ซึ่งใช้ <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 เพื่อรวมแอตทริบิวต์เฉพาะขององค์ประกอบทั้งหมดไว้ในชนิด

คำถามที่พบบ่อย

บทเรียน “คอมโพเนนต์พหุรูปแบบด้วย Prop 'as'” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “คอมโพเนนต์พหุรูปแบบด้วย Prop 'as'” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส React Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส React Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “คอมโพเนนต์พหุรูปแบบด้วย Prop 'as'”

กำหนดชนิดของ prop 'as' เพื่อให้ Button แสดงผลเป็น หรือ พร้อมคงชนิด prop ที่ถูกต้อง คุณปฏิบัติ React Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน React Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน React Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “คอมโพเนนต์พหุรูปแบบด้วย Prop 'as'” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน React Academy นี้ได้ไหม

ได้ บทเรียน React Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ยูเนียนแบบแยกแยะสำหรับรูปแบบคอมโพเนนต์
  2. ชนิดแบบมีเงื่อนไขและชนิดแบบแมปใน React
  3. คอมโพเนนต์พหุรูปแบบด้วย Prop 'as'
  4. ฟอร์มปลอดภัยด้านชนิดข้อมูลและสัญญาผลตอบกลับ API
← กลับไปที่ React Academy