คอมโพเนนต์พหุรูปแบบด้วย 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ยูเนียนแบบแยกแยะสำหรับรูปแบบคอมโพเนนต์
- ชนิดแบบมีเงื่อนไขและชนิดแบบแมปใน React
- คอมโพเนนต์พหุรูปแบบด้วย Prop 'as'
- ฟอร์มปลอดภัยด้านชนิดข้อมูลและสัญญาผลตอบกลับ API