Komponenty złożone w React

Opublikowany: 2022-03-10
Szybkie podsumowanie ↬ Komponent złożony to jeden z zaawansowanych wzorców Reacta, który wykorzystuje interesujący sposób komunikowania relacji między komponentami interfejsu użytkownika i współdzielenia niejawnego stanu poprzez wykorzystanie jawnej relacji rodzic-dziecko.

Komponenty złożone pomagają programistom w tworzeniu bardziej wyrazistych i elastycznych interfejsów API do współdzielenia stanu i logiki w ramach komponentów. Ten samouczek wyjaśnia, jak można to osiągnąć za pomocą interfejsu Context API i React do budowania komponentów przy użyciu tego zaawansowanego wzorca.

Uwaga : aby móc podążać dalej, potrzebujesz podstawowej wiedzy na temat Reacta i sposobu działania Context API.

Co to jest składnik złożony?

Komponenty złożone można powiedzieć, że są wzorcem, który obejmuje stan i zachowanie grupy komponentów, ale nadal daje kontrolę renderowania jego zmiennych części z powrotem użytkownikowi zewnętrznemu.

Z powyższej definicji zwróć uwagę na słowa kluczowe: stan i zachowanie . Pomaga nam to zrozumieć, że komponent złożony radzi sobie ze stanem (tj. jak stan zachowuje się w komponencie, który jest otoczony przez zewnętrznego użytkownika będącego rodzicem komponentu).

Celem komponentów złożonych jest zapewnienie bardziej wyrazistego i elastycznego interfejsu API do komunikacji między komponentami nadrzędnymi i podrzędnymi.

Pomyśl o tym jak o tagach <select> i <option> w HTML:

 <select> <option value="volvo">Volvo</option> <option value="mercedes">Mercedes</option> <option value="audi">Audi</option> </select>

Znacznik select działa razem z znacznikiem option , który jest używany w menu rozwijanym do wybierania elementów w kodzie HTML. Tutaj <select> zarządza stanem interfejsu użytkownika, następnie elementy <option> są konfigurowane tak, jak powinien działać <select> . Komponenty złożone w React są używane do tworzenia deklaratywnego komponentu interfejsu użytkownika, który pomaga uniknąć wiercenia rekwizytów.

Wiercenie rekwizytów polega na przekazywaniu rekwizytów wielu komponentom potomnym. To również nazywają „zapachem kodu”. Najgorsze w ćwiczeniu podpór polega na tym, że gdy komponent nadrzędny zostanie ponownie wyrenderowany, komponenty potomne również zostaną zrenderowane i wywołają efekt domina na komponencie. Dobrym rozwiązaniem byłoby skorzystanie z interfejsu React Context API, któremu również przyjrzymy się później.

Więcej po skoku! Kontynuuj czytanie poniżej ↓

Stosowanie złożonych komponentów w React

Ta sekcja wyjaśnia pakiety, z których możemy skorzystać w naszej aplikacji, które przyjmują złożony wzorzec komponentów budowania komponentów w React. Ten przykład to składnik Menu z pakietu interfejsu użytkownika @reach .

 import { Menu, MenuList, MenuButton, MenuItem, MenuItems, MenuPopover, MenuLink, } from "@reach/menu-button"; import "@reach/menu-button/styles.css";

Oto sposób wykorzystania komponentu Menu :

 function Example() { return ( <Menu> <MenuButton>Actions</MenuButton> <MenuList> <MenuItem>Download</MenuItem> <MenuLink to="view">View</MenuLink> </MenuList> </Menu> ); }

Powyższy przykładowy kod jest jedną z implementacji komponentów złożonych, w której można zobaczyć, że Menu , MenuButton , MenuList , MenuItem i MenuLink zostały zaimportowane z @reach/menu-button . W przeciwieństwie do eksportowania pojedynczego komponentu, ReachUI eksportuje komponent nadrzędny, którym jest Menu towarzyszące jego komponentom podrzędnym, czyli MenuButton , MenuList , MenuItem i MenuLink .

Kiedy należy używać składników złożonych?

Jako programista React powinieneś używać komponentów złożonych, gdy chcesz:

  • Rozwiązywanie problemów związanych z budowaniem komponentów wielokrotnego użytku;
  • Rozwój wysoce spójnych komponentów z minimalnym sprzężeniem;
  • Lepsze sposoby udostępniania logiki między komponentami.

Plusy i minusy komponentów złożonych

Komponent złożony to niesamowity wzorzec React, który można dodać do zestawu narzędzi programistycznych React. W tej sekcji przedstawię zalety i wady używania komponentów złożonych oraz to, czego nauczyłem się podczas budowania komponentów przy użyciu tego wzorca rozwoju.

Plusy

  • Separacja troski
    Posiadanie całej logiki stanu interfejsu użytkownika w komponencie nadrzędnym i przekazywanie jej wewnętrznie do wszystkich komponentów podrzędnych zapewnia jasny podział odpowiedzialności.

  • Zmniejszona złożoność
    W przeciwieństwie do drążenia rekwizytów w celu przekazania właściwości do ich określonych komponentów, właściwości podrzędne przechodzą do odpowiednich komponentów podrzędnych przy użyciu wzorca złożonego komponentu.

Cons

Jedną z głównych wad budowania komponentów w React za pomocą wzorca komponentu złożonego jest to, że tylko direct children komponentu nadrzędnego będą miały dostęp do właściwości, co oznacza, że ​​nie możemy owinąć żadnego z tych komponentów w innym komponencie.

 export default function FlyoutMenu() { return ( <FlyOut> {/* This breaks */} <div> <FlyOut.Toggle /> <FlyOut.List> <FlyOut.Item>Edit</FlyOut.Item> <FlyOut.Item>Delete</FlyOut.Item> </FlyOut.List> </div> </FlyOut> ); }

Rozwiązaniem tego problemu byłoby użycie elastycznego wzorca komponentu złożonego do niejawnego współdzielenia stanu za pomocą interfejsu API React.createContext .

Kontekstowe API umożliwia przekazywanie stanu React przez zagnieżdżone komponenty podczas budowania przy użyciu złożonego wzorca komponentów budujących komponenty w React. Jest to możliwe, ponieważ context umożliwia przekazywanie danych w dół drzewa komponentów bez konieczności ręcznego przekazywania właściwości na każdym poziomie. Korzystanie z Context API zapewnia użytkownikowi końcowemu dużą elastyczność.

Utrzymywanie złożonych komponentów w React

Komponenty złożone zapewniają bardziej elastyczny sposób udostępniania stanu w aplikacjach React, więc korzystanie z komponentów złożonych w aplikacjach React ułatwia utrzymanie i faktyczne debugowanie aplikacji.

Budowanie demo

W tym artykule zbudujemy komponent akordeonu w React przy użyciu wzorca złożonego z komponentów. Komponent, który zamierzamy zbudować w tym samouczku, byłby niestandardowym komponentem akordeonu, który jest elastyczny i udostępnia stan w komponencie za pomocą interfejsu API kontekstu.

Chodźmy!

Przede wszystkim stwórzmy aplikację React, korzystając z:

 npx create-react-app accordionComponent cd accordionComponent npm start

lub

 yarn create react-app accordionComponent cd accordionComponent yarn start

Powyższe polecenia tworzą aplikację React, zmieniają katalog na projekt React i uruchamiają serwer deweloperski.

Uwaga : w tym samouczku użyjemy styled-components aby pomóc w stylizacji naszych komponentów.

Użyj poniższego polecenia, aby zainstalować styled-components :

 yarn add styled-components

lub

 npm install --save styled-components

W folderze src utwórz nowy folder o nazwie components . W tym miejscu mieszkałyby wszystkie nasze komponenty. W folderze components utwórz dwa nowe pliki: accordion.js i accordion.styles.js .

Plik accordion.styles.js zawiera nasze stylizacje dla komponentu Accordion (nasza stylizacja została wykonana za pomocą styled-components ).

 import styled from "styled-components"; export const Container = styled.div` display: flex; border-bottom: 8px solid #222; `;

Powyżej znajduje się przykład stylizacji komponentów przy użyciu biblioteki css-in-js o nazwie styled-components .

W pliku accordion.styles.js dodaj pozostałe style:

 export const Frame = styled.div` margin-bottom: 40px; `; export const Inner = styled.div` display: flex; padding: 70px 45px; flex-direction: column; max-width: 815px; margin: auto; `; export const Title = styled.h1` font-size: 40px; line-height: 1.1; margin-top: 0; margin-bottom: 8px; color: black; text-align: center; `; export const Item = styled.div` color: white; margin: auto; margin-bottom: 10px; max-width: 728px; width: 100%; &:first-of-type { margin-top: 3em; } &:last-of-type { margin-bottom: 0; } `; export const Header = styled.div` display: flex; flex-direction: space-between; cursor: pointer; margin-bottom: 1px; font-size: 26px; font-weight: normal; background: #303030; padding: 0.8em 1.2em 0.8em 1.2em; user-select: none; align-items: center; img { filter: brightness(0) invert(1); width: 24px; user-select: none; @media (max-width: 600px) { width: 16px; } } `; export const Body = styled.div` font-size: 26px; font-weight: normal; line-height: normal; background: #303030; white-space: pre-wrap; user-select: none; overflow: hidden; &.closed { max-height: 0; overflow: hidden; transition: max-height 0.25ms cubic-bezier(0.5, 0, 0.1, 1); } &.open { max-height: 0px; transition: max-height 0.25ms cubic-bezier(0.5, 0, 0.1, 1); } span { display: block; padding: 0.8em 2.2em 0.8em 1.2em; } `;

Zacznijmy budować nasz komponent akordeonowy. W pliku accordion.js dodajmy następujący kod:

 import React, { useState, useContext, createContext } from "react"; import { Container, Inner, Item, Body, Frame, Title, Header } from "./accordion.styles";

Powyżej importujemy useState , useContext i createContext , które pomogą nam zbudować nasz komponent akordeonowy przy użyciu komponentów złożonych.

Dokumentacja Reacta wyjaśnia, że context pomaga w przekazywaniu danych przez drzewo komponentów bez konieczności ręcznego przekazywania właściwości na każdym poziomie.

Patrząc na to, co zaimportowaliśmy wcześniej w naszym pliku accordion.js , zauważysz, że zaimportowaliśmy również nasze style jako komponenty, co pomoże nam szybciej zbudować nasze komponenty.

Stworzymy nasz kontekst dla komponentu, który będzie udostępniał dane komponentom, które ich potrzebują:

 const ToggleContext = createContext(); export default function Accordion({ children, ...restProps }) { return ( <Container {...restProps}> <Inner>{children}</Inner> </Container> ); }

Komponenty Container i Inner z powyższego fragmentu kodu pochodzą z naszego pliku ./accordion.styles.js , w którym utworzyliśmy style dla naszych komponentów przy użyciu styled-components (z biblioteki css-in-js ). Komponent Container mieści w sobie cały Accordion , który budujemy przy użyciu komponentów złożonych.

Tutaj tworzymy obiekt kontekstu za pomocą metody createContext() , więc kiedy React wyrenderuje komponent, który subskrybuje ten obiekt Context, odczyta bieżącą wartość kontekstu z najbliższego pasującego dostawcy znajdującego się powyżej w drzewie.

Następnie tworzymy również nasz podstawowy komponent, którym jest akordeon; zabiera children i wszelkie restProps . To jest nasz komponent nadrzędny, w którym znajdują się komponenty potomne akordeonu.

Utwórzmy inne komponenty potomne w pliku accordion.js :

 Accordion.Title = function AccordionTitle({ children, ...restProps }) { return <Title {...restProps}>{children}</Title>; }; Accordion.Frame = function AccordionFrame({ children, ...restProps }) { return <Frame {...restProps}>{children}</Frame>; };

Zwróć uwagę na . po macierzystym komponencie Akordeon; służy do połączenia komponentu podrzędnego z jego komponentem nadrzędnym.

Kontynuujmy. Teraz dodaj następujące elementy do pliku accordion.js :

 Accordion.Item = function AccordionItem({ children, ...restProps }) { const [toggleShow, setToggleShow] = useState(true); return ( <ToggleContext.Provider value={{ toggleShow, setToggleShow }}> <Item {...restProps}>{children}</Item> </ToggleContext.Provider> ); }; Accordion.ItemHeader = function AccordionHeader({ children, ...restProps }) { const { isShown, toggleIsShown } = useContext(ToggleContext); return ( <Header onClick={() => toggleIsShown(!isShown)} {...restProps}> {children} </Header> ); }; Accordion.Body = function AccordionHeader({ children, ...restProps }) { const { isShown } = useContext(ToggleContext); return ( <Body className={isShown ? "open" : "close"}> <span>{children}</span> </Body> ); };

Więc tutaj tworzymy komponenty Body , Header i Item , które są potomkami komponentu nadrzędnego Accordion . Tutaj może zacząć się robić trudno. Zwróć też uwagę, że każdy utworzony tutaj komponent podrzędny otrzymuje również podporę children i restprops .

Z komponentu potomnego Item zainicjowaliśmy nasz stan za pomocą haka useState i ustawiliśmy go na true. Pamiętaj też, że stworzyliśmy ToggleContext na najwyższym poziomie pliku accordion.js , który jest obiektem Context Object , a kiedy React wyrenderuje komponent, który subskrybuje ten obiekt Context, odczyta bieżącą wartość kontekstu z najbliższego pasującego dostawcy znajdującego się nad nim w drzewie.

Każdy obiekt Context jest dostarczany z komponentem Provider React, który pozwala zużywającym komponentom na subskrybowanie zmian kontekstu.

Komponent provider akceptuje właściwość value , która ma zostać przekazana komponentom zużywającym, które są potomkami tego dostawcy, a tutaj przekazujemy bieżącą wartość stanu, która jest toggleShow i metodą ustawiania wartości bieżącego stanu setToggleShow . Są wartością, która określa, w jaki sposób nasz obiekt kontekstowy będzie współdzielił stan wokół naszego komponentu bez drążenia podpór.

Następnie w naszym komponencie potomnym header Accordion , niszczymy wartości obiektu context, a następnie zmieniamy bieżący stan toggleShow po kliknięciu. Więc to, co próbujemy zrobić, to ukryć lub pokazać nasz akordeon po kliknięciu nagłówka.

W naszym komponencie Accordion.Body niszczymy również toggleShow , który jest bieżącym stanem komponentu, a następnie, w zależności od wartości toggleShow , możemy albo ukryć body, albo pokazać zawartość komponentu Accordion.Body .

To wszystko dla naszego pliku accordion.js .

W tym miejscu możemy zobaczyć, jak wszystko, czego nauczyliśmy się o komponentach Context i Compound components łączy się w całość. Ale wcześniej utwórzmy nowy plik o nazwie data.json i wklejmy do niego poniższą treść:

 [ { "id": 1, "header": "What is Netflix?", "body": "Netflix is a streaming service that offers a wide variety of award-winning TV programs, films, anime, documentaries and more – on thousands of internet-connected devices.\n\nYou can watch as much as you want, whenever you want, without a single advert – all for one low monthly price. There's always something new to discover, and new TV programs and films are added every week!" }, { "id": 2, "header": "How much does Netflix cost?", "body": "Watch Netflix on your smartphone, tablet, smart TV, laptop or streaming device, all for one low fixed monthly fee. Plans start from £5.99 a month. No extra costs or contracts." }, { "id": 3, "header": "Where can I watch?", "body": "Watch anywhere, anytime, on an unlimited number of devices. Sign in with your Netflix account to watch instantly on the web at netflix.com from your personal computer or on any internet-connected device that offers the Netflix app, including smart TVs, smartphones, tablets, streaming media players and game consoles.\n\nYou can also download your favorite programs with the iOS, Android, or Windows 10 app. Use downloads to watch while you're on the go and without an internet connection. Take Netflix with you anywhere." }, { "id": 4, "header": "How do I cancel?", "body": "Netflix is flexible. There are no annoying contracts and no commitments. You can easily cancel your account online with two clicks. There are no cancellation fees – start or stop your account at any time." }, { "id": 5, "header": "What can I watch on Netflix?", "body": "Netflix has an extensive library of feature films, documentaries, TV programs, anime, award-winning Netflix originals, and more. Watch as much as you want, any time you want." } ]

To są dane, z którymi będziemy pracować, aby przetestować nasz akordeon.

Więc idźmy dalej. Prawie skończyliśmy i wierzę, że wiele się nauczyłeś, śledząc ten artykuł.

W tej sekcji zebramy wszystko, nad czym pracowaliśmy, i poznamy komponenty złożone, aby móc użyć tego w naszym pliku App.js , aby użyć funkcji Array.map do wyświetlenia danych, które już mamy w sieci strona. Zauważ również, że nie było użycia stanu w App.js ; wszystko, co zrobiliśmy, to przekazanie danych do poszczególnych komponentów, a Context API zajęło się wszystkim innym.

Przejdźmy teraz do ostatniej części. W App.js wykonaj następujące czynności:

 import React from "react"; import Accordion from "./components/Accordion"; import faqData from "./data"; export default function App() { return ( <Accordion> <Accordion.Title>Frequently Asked Questions</Accordion.Title> <Accordion.Frame> {faqData.map((item) => ( <Accordion.Item key={item.id}> <Accordion.Header>{item.header}</Accordion.Header> <Accordion.Body>{item.body}</Accordion.Body> </Accordion.Item> ))} </Accordion.Frame> </Accordion> ); }

W twoim pliku App.js zaimportowaliśmy nasz akordeon komponentu złożonego ze ścieżki pliku, a następnie zaimportowaliśmy również nasze dane fikcyjne, zmapowane przez dane fikcyjne, aby uzyskać poszczególne elementy w naszym pliku danych, a następnie wyświetliliśmy je zgodnie z odpowiednimi komponentu, można również zauważyć, że wszystko, co musieliśmy zrobić, to przekazać dzieci do odpowiedniego komponentu, Context API dba o to, aby dotarł on do właściwego komponentu i nie było wiercenia podpór.

Tak powinien wyglądać nasz finalny produkt:

Ostateczny wygląd naszego komponentu akordeonowego
Ostateczny wygląd naszego komponentu akordeonowego. (duży podgląd)

Alternatywa dla komponentów złożonych

Alternatywą do używania komponentów złożonych byłoby skorzystanie z API Render Props. Termin Render Prop w React odnosi się do techniki współdzielenia kodu pomiędzy komponentami Reacta przy użyciu właściwości, której wartością jest funkcja. Komponent z właściwością renderowania przyjmuje funkcję, która zwraca element React i wywołuje go zamiast implementować własną logikę renderowania.

Przekazywanie danych z komponentu do komponentu podrzędnego, który potrzebuje tych danych, może skutkować ćwiczeniem prop drążąc, gdy komponenty są zagnieżdżone w sobie. Jest to zaleta używania Context do udostępniania danych między komponentami w porównaniu z użyciem metody render prop.

Wniosek

W tym artykule dowiedzieliśmy się o jednym z zaawansowanych wzorców Reacta, którym jest złożony wzorzec komponentów. Jest to niesamowita metoda budowania komponentów wielokrotnego użytku w React przy użyciu wzorca złożonego komponentu do budowania komponentu, który oferuje dużą elastyczność w komponencie. Nadal możesz zdecydować się na użycie Prop renderowania, jeśli elastyczność nie jest obecnie tym, czego wymaga Twój komponent.

Komponenty złożone są najbardziej przydatne w systemach projektowania budynków. Przeszliśmy również przez proces udostępniania stanu w ramach komponentów za pomocą Context API.

  • Kod do tego samouczka można znaleźć na Codesandbox.