Logo NFU StudioLogo medium icon
wróć do listy
Kodowe

Kompozycja Reactowa czyli elastyczność ponad przewidywalność.

Dlaczego do znudzenia warto utrwalać wzorzec kompozycji w React. Dlaczego biblioteki takie jak Shadcn rządzą na polu frontendowych rozwiązań.
4 minuty czytania

Początek znanej debaty nad Reactem

Znane paradygmaty programowania obiektowego - dziedziczenie, abstrakcja i polimorfizm, są wpajane młodym programistom od początków nauki. Nie ma w tym nic złego. Podstawy są ważne i należy je przyswoić. Są jednak takie technologie, w których np: dziedziczenie się nie sprawdza. Jedną z takich technologii jest nasz znany i lubiany React. Kolejnym znanym społeczności zagadnieniem, jest przekazywanie właściwości komponentów. Dlaczego nawet dokumentacja głosi kult kompozycji? Temat ten pojawia się w wielu artukułach i postach, dlatego NFU postanowiło dorzucić swoje 5 groszy, w odniesieniu do znanych bibliotek frontendowych.

Dlaczego właśnie ta cała kompozycja?

Spójrzmy najpierw na rozwiązanie, w którym funckja renderująca kompoment, przyjmuje propsy i renderuje je w odpowiednich miejscach wewnątrz komponentu.

function Card(props) {
  return (
    <div className="card">
      <div className="card-header">
        <h2>{props.title}</h2>
        <p>{props.description}</p>
      </div>
      <div className="card-content">
        <p>{props.content}</p>
      </div>
      <div className="card-footer">
        <p>{props.footer}</p>
      </div>
    </div>
  );
}

Będzie działać. Tylko co w przypadku kiedy trzeba to będzie rozbudować? Poprostu załadujemy więcej propsów? Czyli w zasadzie można to sprowadzić do klasyka:

PROPSY

Skalowalność leży. Czyli jest to całkiem do kitu? No otóż nie do końca. Można wymienić zalety takie jak przewiwalność. Cieżko będzie źle przekazać parametry, bo wiemy co jest potrzebne do prawidłowego działania komponentu.

Z pomocą przychodzi nam Reactowa kompozycja. Wzorzec kompozycji w React polega na tworzeniu bardziej złożonych struktur, poprzez składanie prostszych obiektów w hierarchiczną strukturę, a nie rozszerzaniu funkcjonalności już istniejących komponentów. Dla przykładu, spójrzmy na potencjalny kod nagłówka naszej karty:

const CardHeader = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn("flex flex-col space-y-1.5 p-6", className)}
    {...props}
  />
))
CardHeader.displayName = "CardHeader"

Składając klocek po klocku, uzyskujemy właśnie opisywaną kompozycję. Finalny kod naszej karty może prezentować się następująco:

<Card>
  <CardHeader>
    <CardTitle>Card Title</CardTitle>
    <CardDescription>Card Description</CardDescription>
  </CardHeader>
  <CardContent>
    <p>Card Content</p>
  </CardContent>
  <CardFooter>
    <p>Card Footer</p>
  </CardFooter>
</Card>

Każdy z tych pojedynczych komponentów, oprócz wykorzystania dla naszej karty można przy okazji wykorzystać w innych miejscach. Do innych zalet tego wzorca możemy zaliczyć:

  • Elastyczność - używamy jak chcemy i kiedy chcemy, szybko i sprawnie możemy zmienić układ części komponentu.
  • Skalowalność - rozbudowa komponentów nie stanowi żadnego problemu.
  • Łatwa konserwacja - każdy element może być zarządzany niezależnie, co ułatwia utrzymanie kodu.

Czy istnieją wady kompozycji? Istnieje ryzyko wprowadzenia zbyt wielu zależności pomiędzy komponentami, co może skutować trudnościami przy modyfikacji. Gdy struktura klocków jest już całkiem rozbudowana to samo debugowanie może być dosyć czasochłonne. Co ciekawe, jak to zazwyczaj bywa, w różnych przypadkach sprawdzają się różne podejścia i nie można powiedzieć, że jedno podejście jest zawsze lepsze od drugiego. Dużo zależy od charakteru komponentu.

A komu to potrzebne?

Jakieś żywe przykłady gdzie z tego korzystamy? Sama idea jest wpajana developerom nawet przez DOKUMENTACJĘ. Ale czy przypadkiem przedstawiony wyżej kod wydaje się być znajomy? To nic innego jak jeden z komponentów z biblioteki SHADCN. Jest ona sztandarowym przykładem wykorzystania omawianej w poście kompozycji. Sami korzystamy w każdym projekcie, które realizujemy, z resztą nie tylko my. Repo wykęciło 51 tysięcy gwiazdek (w dniu publikacji).

// zwykłe stylowanie przy pomocy Tailwind
export default function Home() {
  return (
    <>
      <button className="p-2 bg-orange-400">Click me</button>
    </>
  );
}

// stylowanie przy pomocy SHADCN

import { Button } from "@/components/ui/button";

export default function Home() {
  return (
    <>
      <Button variant="outline">Button</Button>
    </>
  );
}

Dlaczego wszyscy tak lubią tą bibliotekę? Przede wszystkim za intuicyjność i konstrukcję dostosowaną do szybkiej rozbudowy czy modyfikacji komponentów.

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean
}
 
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : "button"
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    )
  }
)
Button.displayName = "Button"

Tak skonstuowany komponent jest gotowy do przyjęcia elementów potomnych, oraz gotowy do wielokrotnego wykorzystania w różnych miejsach projektu.

Podsumowanie

Warto dobrze zrozumieć i stosować wzorzec kompozycji w swoich projektach Reactowych, ponieważ przynosi on realne korzyści zarówno w procesie tworzenia, jak i utrzymywania aplikacji po stronie frontu. Dla potwierdzenia najlepiej spojrzeć właśnie na biblioteki gigantów frontowych. Skoro oni zbudowali na tym swój potencjał to musi działać!

jeszcze jeden i starczy...

Design

Polecane i przydatne pluginy do Figmy

Zobacz przydatne pluginy, które ulepszają pracę w Figmie
Przeczytaj post - Polecane i przydatne pluginy do Figmy

Projekty

Projekt strony internetowej - ważniejszy niż implementacja?

Po co jest faza projektowa strony internetowej i co powinno zostać ustalone przed rozpoczęciem implementacji. Jak projektować żeby to miało ręce i nogi a do tego przynosiło firmie zyski.
Przeczytaj post - Projekt strony internetowej - ważniejszy niż implementacja?

Design

Auto Layout w Figmie - wprowadzenie na dobry początek

Jeśli chcesz szybciej i przyjemniej projektować w Figmie to zapoznaj się jak używać Auto Layout.
Przeczytaj post - Auto Layout w Figmie - wprowadzenie na dobry początek