React Academy · Lektion

Polymorfa komponenter med propen 'as'

Typa propen 'as' så att en Button renderas som eller samtidigt som korrekta prop-typer bevaras.

Lektion 3 av 413 steg

Polymorfa komponenter med propen 'as' är en gratis lektion i React Academy på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för React Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i React Academy innehåller totalt 4 lektioner.

Vad är en polymorf komponent?

En polymorf komponent renderas som olika HTML-element eller komponenter baserat på en as-prop – till exempel en Button som renderas som <a> eller <button> samtidigt som korrekta TypeScript-typer bevaras.

En enkel as-prop (utan TypeScript)

En grundläggande polymorf implementation utan generics – den förlorar typsäkerheten men visar konceptet.

function Box({ as: Tag = 'div', children, ...props }) {
  return <Tag {...props}>{children}</Tag>;
}

// Usage:
<Box as="section" className="hero">...</Box>
<Box as="article">...</Box>

Typad as-prop med generics

Lägg till en generisk typparameter för att härleda korrekta props för det element som as renderas som.

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} />;
}

Med ref-stöd

Lägg till stöd för forwardRef samtidigt som den polymorfa typningen bevaras.

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-härledning i praktiken

När as='a' anges vet TypeScript att komponenten accepterar ankar- specifika props som href och target, men inte knappspecifika sådana som 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

Utöka med egna props

Lägg till komponentspecifika props bredvid den polymorfa basen genom att sprida in dem i typdefinitionen.

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}
    />
  );
}

Praktiskt användningsfall: länk som renderas som RouterLink

En Button som renderas som React Routers Link när to anges, eller som en vanlig knapp i annat fall.

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} />;
}

Textkomponent för designsystem

En polymorf Text-komponent som som standard använder <p> men kan renderas som h1–h6, span eller 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'

Begränsningar för as-propen

Använd extends React.ElementType för att acceptera både strängar för HTML-element ('div', 'a') och React-komponenter.

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 }} />

Undvik vanliga fallgropar

Sprid inte as-propen till elementet (den är inte ett giltigt HTML-attribut). Destrukturera alltid bort den innan återstående props sprids.

// 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
}

Prestandaövervägande

Polymorfa komponenter har minimal prestandakostnad – as-propen är bara en variabel som innehåller en sträng för elementtypen eller en komponentreferens.

Snabbkontroll

Varför bör as-propen destruktureras innan återstående props sprids till elementet i en polymorf komponent?

Sammanfattning

Polymorfa komponenter använder en generisk prop, as?: E extends React.ElementType, för att renderas som valfritt element samtidigt som korrekta TypeScript-props bevaras. Destrukturera as innan återstående props sprids. Använd React.ComponentPropsWithoutRef för att inkludera alla elementspecifika attribut i typen.

Gratis att börja

Lär dig React med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
88
Lektioner
324

Vanliga frågor

Är lektionen ”Polymorfa komponenter med propen 'as'” gratis?

Ja – hela texten till ”Polymorfa komponenter med propen 'as'” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i React Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i React Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Polymorfa komponenter med propen 'as'”?

Typa propen 'as' så att en Button renderas som eller samtidigt som korrekta prop-typer bevaras. Ni övar på React Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig React Academy?

Du behöver inga förkunskaper. Utbildningen i React Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.

Hur lång tid tar lektionen ”Polymorfa komponenter med propen 'as'”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här React Academy-lektionen?

Ja. Varje React Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Discriminated unions för komponentvarianter
  2. Villkorliga och mappade typer i React
  3. Polymorfa komponenter med propen 'as'
  4. Typsäkra formulär och kontrakt för API-svar
← Tillbaka till React Academy