0Pricing
React Academy · Lekcja

Komponenty polimorficzne z propsem 'as'

Typowanie propsa 'as', aby Button renderował się jako lub , przy zachowaniu prawidłowych typów propsów.

Komponenty polimorficzne z propsem 'as' to bezpłatna lekcja React Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej React Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs React Academy zawiera 4 lekcji w sumie.

Czym jest komponent polimorficzny

Komponent polimorficzny renderuje różne elementy HTML lub komponenty w zależności od propsa as — np. komponent Button, który renderuje się jako <a> lub <button>, zachowując przy tym poprawne typy TypeScript.

Prosty props as (bez TypeScriptu)

Podstawowa implementacja polimorficzna bez generyków — traci bezpieczeństwo typów, ale pokazuje tę koncepcję.

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

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

Typowany props as z generykami

Dodaj parametr typu generycznego, aby wywnioskować poprawne propsy dla elementu wskazanego przez 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} />;
}

Obsługa ref

Dodaj obsługę forwardRef, zachowując polimorficzne typowanie.

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

Wnioskowanie TypeScriptu w praktyce

Po ustawieniu as='a' TypeScript wie, że komponent akceptuje propsy właściwe dla elementu kotwicy, takie jak href i target, ale nie propsy właściwe dla przycisku, takie jak 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

Rozszerzanie o własne propsy

Dodaj propsy specyficzne dla komponentu obok polimorficznej bazy, uwzględniając je w definicji typu.

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

Praktyczny przypadek: Link renderowany jako RouterLink

Komponent Button, który renderuje Link biblioteki React Router, gdy podano to, albo zwykły przycisk w przeciwnym razie.

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

Komponent Text w systemie projektowym

Polimorficzny komponent Text, który domyślnie renderuje się jako <p>, ale może renderować się jako h1–h6, span lub 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'

Ograniczenia propsa as

Użyj extends React.ElementType, aby akceptować zarówno ciągi znaków reprezentujące elementy HTML ('div', 'a'), jak i komponenty 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 }} />

Unikanie typowych pułapek

Nie rozpraszaj propsa as na elemencie (nie jest poprawnym atrybutem HTML). Zawsze wyodrębnij go przed rozproszeniem pozostałych propsów.

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

Aspekt wydajnościowy

Komponenty polimorficzne mają minimalny narzut wydajnościowy — props as jest po prostu zmienną przechowującą łańcuch znaków typu elementu lub referencję do komponentu.

Szybki sprawdzian

Dlaczego należy wyodrębnić props as przed rozproszeniem pozostałych propsów na elemencie w komponencie polimorficznym?

Podsumowanie

Komponenty polimorficzne używają generycznego propsa as?: E extends React.ElementType, aby renderować dowolny element z zachowaniem poprawnych propsów TypeScriptu. Wyodrębnij as przed rozproszeniem pozostałych propsów. Użyj React.ComponentPropsWithoutRef, aby uwzględnić w typie wszystkie atrybuty właściwe dla danego elementu.

Często zadawane pytania

Czy lekcja „Komponenty polimorficzne z propsem 'as'” jest bezpłatna?

Tak — pełny tekst „Komponenty polimorficzne z propsem 'as'” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu React Academy, przejdź na CoddyKit PRO. Kurs React Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Komponenty polimorficzne z propsem 'as'”?

Typowanie propsa 'as', aby Button renderował się jako lub , przy zachowaniu prawidłowych typów propsów. Ćwiczysz React Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć React Academy?

Nie wymagamy żadnego doświadczenia. React Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Komponenty polimorficzne z propsem 'as'”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji React Academy?

Tak. Każda lekcja React Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Rozłączne sumy dla wariantów komponentów
  2. Typy warunkowe i mapowane w React
  3. Komponenty polimorficzne z propsem 'as'
  4. Formularze bezpieczne typowo i kontrakty odpowiedzi API
← Powrót do React Academy