Tworzenie komponentów polimorficznych za pomocą React i TypeScript
Dodanie polimorfizmu do komponentów React sprawi, że będą one bardziej wszechstronne, ponieważ konsumenci będą mogli zdefiniować element renderowany w DOM.
Istnieją ważne kroki, które należy wykonać podczas budowania tych komponentów, więc zaczynajmy!
Dlaczego potrzebujemy komponentów polimorficznych?
Być może zauważyłeś, że w niektórych bibliotekach, takich jak ( Material UI lub Chakra UI ), niektóre komponenty mają opcję zezwalania na atrybut aslub elementTyperekwizyt. Jest to ważne dla dostosowania, ale także dla poprawy dostępności poprzez umożliwienie nam używania elementów semantycznych HTML podczas renderowania naszych komponentów.
Dodawanie aswłaściwości do komponentu React
Zobaczmy, jak moglibyśmy zaimplementować coś podobnego do tych bibliotek — zaczniemy od prostego Textkomponentu React.
const Text = ({ as, children, ...rest }) => {
const Component = as || "span";
return <Component {...rest}>{children}</Component>;
};
export default function App() {
return <Text>Text goes here</Text>; // Will render a span by default
}
<Text as="main">Text goes here</Text>;
<Text as="p">Text goes here</Text>;
<Text as="section">Text goes here</Text>;
<Text as="a" href="www.example.com">Text goes here</Text>
Działa jak marzenie! Och, ale czekaj…
<Text as="p" href="www.example.com">
Text goes here
</Text>
Nadchodzi TypeScript
W tym miejscu pojawia się nasz najlepszy przyjaciel TypeScript.
Musimy upewnić się, że Textrekwizyty komponentu są silnie wpisane, aby można je było sprawdzić statycznie podczas procesu programowania.
Plan polega na tym, aby nasza aswłaściwość akceptowała dowolny prawidłowy element HTML, a następnie w jakiś sposób określała, które atrybuty HTML są prawidłowe na podstawie tego samego elementu (np. atag powinien zezwalać na hrefatrybut).
Tworzenie naszych typów
Zacznijmy od ustawienia typu dla asrekwizytu.
import { ElementType } from "react";
type AsProp<T extends ElementType> = {
/**
* The HTML element used for the root node.
*/
as?: T;
};
Nasz typ Tjest ograniczony do typów, które wywodzą się ElementTypez Reacta, tj. dowolnych prawidłowych elementów HTML.
import { ComponentPropsWithoutRef } from "react";
ComponentPropsWithoutRef<T>
Omit<ComponentPropsWithoutRef<T>, keyof Props<T>>
Props<T> & Omit<ComponentPropsWithoutRef<T>, keyof Props<T>>
Nasze połączone typy powinny wyglądać mniej więcej tak:
type TextProps<T extends ElementType> = PropsWithChildren<AsProp<T>> &
Omit<ComponentPropsWithoutRef<T>, keyof AsProp<T>>;
Wreszcie TextPropsma wszystko, czego potrzebujemy Text! Złóżmy wszystko razem i dodajmy typ do naszego Textkomponentu:
import {
ElementType,
ComponentPropsWithoutRef,
PropsWithChildren
} from "react";
type AsProp<T extends ElementType> = {
/**
* The HTML element used for the root node.
*/
as?: T;
};
type TextProps<T extends ElementType> = PropsWithChildren<AsProp<T>> &
Omit<ComponentPropsWithoutRef<T>, keyof AsProp<T>>;
const Text = <T extends ElementType = "span">({
as,
children,
...rest
}: TextProps<T>) => {
const Component = as || "span";
return <Component {...rest}>{children}</Component>;
};
Najlepszą rzeczą w naszej konfiguracji jest to, że now ...restjest również mocno wpisany.
Więc to powinno działać:
<Text as="a" href="www.google.com">
Text goes here
</Text>
<Text as="main" href="www.google.com">
Text goes here
</Text>

![Czym w ogóle jest lista połączona? [Część 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































