Zusammengesetzte Komponenten in Reaktion

Veröffentlicht: 2022-03-10
Kurze Zusammenfassung ↬ Eine zusammengesetzte Komponente ist eines der fortgeschrittenen Muster von React, das eine interessante Möglichkeit nutzt, um die Beziehung zwischen UI-Komponenten zu kommunizieren und den impliziten Zustand zu teilen, indem es eine explizite Eltern-Kind-Beziehung nutzt.

Zusammengesetzte Komponenten helfen Entwicklern dabei, aussagekräftigere und flexiblere APIs zu erstellen, um Zustand und Logik innerhalb von Komponenten gemeinsam zu nutzen. In diesem Tutorial wird erläutert, wie dies mithilfe der Kontext-API und React erreicht werden kann, um Komponenten mithilfe dieses erweiterten Musters zu erstellen.

Hinweis : Um mitmachen zu können, benötigen Sie ein grundlegendes Verständnis von React und der Funktionsweise der Context-API.

Was ist eine zusammengesetzte Komponente?

Zusammengesetzte Komponenten können als ein Muster bezeichnet werden, das den Zustand und das Verhalten einer Gruppe von Komponenten umschließt, aber dennoch die Wiedergabesteuerung ihrer variablen Teile an den externen Benutzer zurückgibt.

Beachten Sie aus der obigen Definition die Schlüsselwörter: Zustand und Verhalten . Dies hilft uns zu verstehen, dass sich zusammengesetzte Komponenten mit dem Zustand befassen (dh wie sich der Zustand über eine Komponente verhält, die von einem externen Benutzer eingeschlossen ist, der der Elternteil der Komponente ist).

Das Ziel zusammengesetzter Komponenten besteht darin, eine ausdrucksstärkere und flexiblere API für die Kommunikation zwischen den Eltern- und den Kindkomponenten bereitzustellen.

Stellen Sie es sich wie die Tags <select> und <option> in HTML vor:

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

Das select -Tag arbeitet mit dem option -Tag zusammen, das für ein Dropdown-Menü verwendet wird, um Elemente in HTML auszuwählen. Hier verwaltet <select> den Zustand der Benutzeroberfläche, dann werden die <option> -Elemente so konfiguriert, wie <select> funktionieren soll. Zusammengesetzte Komponenten in React werden verwendet, um eine deklarative UI-Komponente zu erstellen, die hilft, Prop Drilling zu vermeiden.

Beim Stützenbohren werden Stützen an mehrere untergeordnete Komponenten weitergegeben. Dies wird auch als „Code Smell“ bezeichnet. Das Schlimmste am Prop Drilling ist, dass beim erneuten Rendern der übergeordneten Komponente die untergeordneten Komponenten ebenfalls erneut gerendert werden und einen Dominoeffekt auf der Komponente verursachen. Eine gute Lösung wäre die Verwendung der React Context API, auf die wir später noch eingehen werden.

Mehr nach dem Sprung! Lesen Sie unten weiter ↓

Anwenden zusammengesetzter Komponenten in React

In diesem Abschnitt werden die Pakete erläutert, die wir in unserer Anwendung verwenden können, die das zusammengesetzte Komponentenmuster von Komponenten in React übernehmen. Dieses Beispiel ist eine Menu -Komponente aus dem @reach UI-Paket.

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

So können Sie die Menu -Komponente verwenden:

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

Der obige Beispielcode ist eine der Implementierungen zusammengesetzter Komponenten, in denen Sie sehen, dass Menu , MenuButton , MenuList , MenuItem und MenuLink alle aus @reach/menu-button importiert wurden. Im Gegensatz zum Exportieren einer einzelnen Komponente exportiert ReachUI eine übergeordnete Komponente, nämlich Menu , die ihre untergeordneten Komponenten begleitet, nämlich MenuButton , MenuList , MenuItem und MenuLink .

Wann sollten Sie zusammengesetzte Komponenten verwenden?

Als React-Entwickler sollten Sie zusammengesetzte Komponenten verwenden, wenn Sie:

  • Lösen Sie Probleme im Zusammenhang mit dem Erstellen wiederverwendbarer Komponenten;
  • Entwicklung hochkohäsiver Komponenten mit minimaler Kopplung;
  • Bessere Möglichkeiten, Logik zwischen Komponenten zu teilen.

Vor- und Nachteile zusammengesetzter Komponenten

Eine zusammengesetzte Komponente ist ein großartiges React-Muster, das Sie Ihrem React-Entwickler-Toolkit hinzufügen können. In diesem Abschnitt werde ich die Vor- und Nachteile der Verwendung zusammengesetzter Komponenten darlegen und was ich aus der Erstellung von Komponenten mit diesem Entwicklungsmuster gelernt habe.

Vorteile

  • Trennung von Bedenken
    Die gesamte UI-Zustandslogik in der übergeordneten Komponente zu haben und diese intern an alle untergeordneten Komponenten zu kommunizieren, sorgt für eine klare Aufteilung der Verantwortlichkeiten.

  • Reduzierte Komplexität
    Im Gegensatz zum Requisiten-Bohren, um Eigenschaften an ihre spezifischen Komponenten weiterzugeben, gehen untergeordnete Requisiten unter Verwendung des zusammengesetzten Komponentenmusters zu ihren jeweiligen untergeordneten Komponenten.

Nachteile

Einer der Hauptnachteile beim Erstellen von Komponenten in React mit dem zusammengesetzten Komponentenmuster besteht darin, dass nur direct children der übergeordneten Komponente Zugriff auf die Requisiten haben, was bedeutet, dass wir keine dieser Komponenten in eine andere Komponente einschließen können.

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

Eine Lösung für dieses Problem wäre die Verwendung des flexiblen zusammengesetzten Komponentenmusters, um den Zustand mithilfe der React.createContext API implizit zu teilen.

Die Kontext-API ermöglicht es, den React-Zustand durch verschachtelte Komponenten zu übergeben, wenn mithilfe des zusammengesetzten Komponentenmusters zum Erstellen von Komponenten in React erstellt wird. Dies ist möglich, da der context eine Möglichkeit bietet, Daten im Komponentenbaum nach unten weiterzugeben, ohne dass Requisiten auf jeder Ebene manuell weitergegeben werden müssen. Die Verwendung der Kontext-API bietet dem Endbenutzer eine Menge Flexibilität.

Zusammengesetzte Komponenten in Reaktion halten

Zusammengesetzte Komponenten bieten eine flexiblere Möglichkeit, den Status innerhalb von React-Anwendungen zu teilen, sodass die Verwendung von zusammengesetzten Komponenten in Ihren React-Anwendungen die Wartung und das eigentliche Debuggen Ihrer Apps vereinfacht.

Erstellen einer Demo

In diesem Artikel werden wir eine Akkordeon-Komponente in React erstellen, indem wir das zusammengesetzte Komponentenmuster verwenden. Die Komponente, die wir in diesem Lernprogramm erstellen werden, wäre eine maßgeschneiderte Akkordeonkomponente , die flexibel ist und den Status innerhalb der Komponente mithilfe der Kontext-API teilt.

Lass uns gehen!

Lassen Sie uns zunächst eine React-App erstellen, indem Sie Folgendes verwenden:

 npx create-react-app accordionComponent cd accordionComponent npm start

oder

 yarn create react-app accordionComponent cd accordionComponent yarn start

Die obigen Befehle erstellen eine React-App, ändern das Verzeichnis zum React-Projekt und starten den Entwicklungsserver.

Hinweis : In diesem Tutorial werden wir styled-components verwenden, um unsere Komponenten zu stylen.

Verwenden Sie den folgenden Befehl, um styled-components zu installieren:

 yarn add styled-components

oder

 npm install --save styled-components

Erstellen Sie im src- Ordner einen neuen Ordner namens components . Hier würden alle unsere Komponenten leben. Erstellen Sie im Ordner „ components “ zwei neue Dateien: „ accordion.js “ und „ accordion.styles.js “.

Die Datei „ accordion.styles.js “ enthält unser Styling für die Accordion -Komponente (unser Styling wurde mit styled-components erstellt).

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

Oben ist ein Beispiel für das Styling von Komponenten mit der css-in-js Bibliothek namens styled-components .

Fügen Sie in der Datei „ accordion.styles.js “ die restlichen Stile hinzu:

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

Beginnen wir mit dem Bau unserer Akkordeonkomponente. Fügen wir in der Datei „ accordion.js “ den folgenden Code hinzu:

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

Oben importieren wir die useState , useContext und createContext , die uns helfen werden, unsere Akkordeonkomponente mit zusammengesetzten Komponenten zu erstellen.

Die React-Dokumentation erklärt, dass der context dazu beiträgt, Daten durch den Komponentenbaum zu leiten, ohne Props auf jeder Ebene manuell weitergeben zu müssen.

Wenn Sie sich ansehen, was wir zuvor in unsere Datei „ accordion.js “ importiert haben, werden Sie feststellen, dass wir unsere Stile auch als Komponenten importiert haben, was uns dabei helfen wird, unsere Komponenten schneller zu erstellen.

Wir werden fortfahren und unseren Kontext für die Komponente erstellen, die Daten mit den Komponenten teilt, die sie benötigen:

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

Die Container und die Inner -Komponenten aus dem obigen Code-Snippet stammen aus unserer ./accordion.styles.js , in der wir mithilfe der styled-components (aus der css-in-js Bibliothek) Stile für unsere Komponenten erstellt haben. Die Container -Komponente beherbergt das gesamte Accordion , das wir bauen, indem wir zusammengesetzte Komponenten verwenden.

Hier erstellen wir ein Kontextobjekt mit der Methode createContext() . Wenn React also eine Komponente rendert, die dieses Kontextobjekt abonniert, liest es den aktuellen Kontextwert vom am besten passenden Provider darüber im Baum.

Dann erstellen wir auch unsere Basiskomponente, die das Akkordeon ist; es braucht die children und eventuell restProps . Dies ist unsere übergeordnete Komponente, die die untergeordneten Komponenten des Akkordeons beherbergt.

Lassen Sie uns weitere untergeordnete Komponenten in der Datei „ accordion.js “ erstellen:

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

Beachten Sie die . nach der übergeordneten Accordion-Komponente; Dies wird verwendet, um die untergeordnete Komponente mit ihrer übergeordneten Komponente zu verbinden.

Lass uns weitermachen. Fügen Sie nun Folgendes zur Datei „ accordion.js “ hinzu:

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

Hier erstellen wir also eine Body - , Header - und Item - Komponente , die alle Kinder der übergeordneten Komponente Accordion sind . Hier könnte es schwierig werden. Beachten Sie auch, dass jede hier erstellte restprops children .

Von der untergeordneten Komponente „ Item “ haben wir unseren Status mithilfe des useState -Hooks initialisiert und auf „true“ gesetzt. Denken Sie dann auch daran, dass wir einen ToggleContext auf der obersten Ebene der Datei „ accordion.js “ erstellt haben, die ein Context Object ist, und wenn React eine Komponente rendert, die dieses Context-Objekt abonniert, liest es den aktuellen Kontextwert vom nächsten passenden Provider darüber im Baum.

Jedes Context-Objekt verfügt über eine Provider React-Komponente, die es verbrauchenden Komponenten ermöglicht, Kontextänderungen zu abonnieren.

Die provider -Komponente akzeptiert eine value -Prop, die an verbrauchende Komponenten übergeben werden soll, die Nachkommen dieses Providers sind, und hier übergeben wir den aktuellen Zustandswert, der toggleShow und die Methode zum Festlegen des Werts des aktuellen Zustands setToggleShow . Sie sind der Wert, der bestimmt, wie unser Kontextobjekt den Zustand um unsere Komponente herum ohne Prop Drilling teilt.

Dann zerstören wir in unserer header -Komponente des Accordion die Werte des Kontextobjekts und ändern dann den aktuellen Zustand der toggleShow beim Klicken. Wir versuchen also, unser Akkordeon zu verstecken oder anzuzeigen, wenn auf die Kopfzeile geklickt wird.

In unserer Accordion.Body -Komponente zerstören wir auch die toggleShow , die den aktuellen Zustand der Komponente darstellt, dann können wir abhängig vom Wert von toggleShow entweder den Body ausblenden oder den Inhalt der Accordion.Body -Komponente anzeigen.

Das ist also alles für unsere accordion.js -Datei.

Hier sehen wir nun, wie alles zusammenkommt, was wir über Context und zusammengesetzte Compound components gelernt haben. Aber vorher erstellen wir eine neue Datei namens data.json und fügen den folgenden Inhalt darin ein:

 [ { "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." } ]

Dies sind die Daten, mit denen wir arbeiten werden, um unsere Akkordeon-Komponente zu testen.

Also lass uns weitermachen. Wir sind fast fertig und ich glaube, Sie haben viel gelernt, indem Sie diesem Artikel gefolgt sind.

In diesem Abschnitt werden wir alles zusammenführen, woran wir gearbeitet und was wir über zusammengesetzte Komponenten gelernt haben, um es in unserer App.js -Datei verwenden zu können, um die Array.map Funktion zu verwenden, um die Daten anzuzeigen, die wir bereits im Web haben Seite. Beachten Sie auch, dass innerhalb von App.js kein Status verwendet wurde. Alles, was wir getan haben, war, Daten an die spezifischen Komponenten weiterzugeben, und die Kontext-API kümmerte sich um alles andere.

Nun zum letzten Teil. Gehen Sie in Ihrer App.js wie folgt vor:

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

In Ihrer App.js -Datei haben wir unser Compound Component Accordion aus dem Dateipfad importiert, dann auch unsere Dummy-Daten importiert, durch die Dummy-Daten gemappt, um die einzelnen Elemente in unserer Datendatei zu erhalten, und sie dann entsprechend der jeweiligen angezeigt Komponente, würden Sie auch feststellen, dass wir nur die untergeordneten Elemente an die jeweilige Komponente übergeben mussten, die Kontext-API kümmert sich darum, dass sie die richtige Komponente erreicht, und es gab kein Requisitenbohren.

So sollte unser Endprodukt aussehen:

Endgültiger Look unserer Akkordeon-Komponente
Endgültiger Look unserer Akkordeon-Komponente. (Große Vorschau)

Alternative zu zusammengesetzten Komponenten

Eine Alternative zur Verwendung zusammengesetzter Komponenten wäre die Verwendung der Render Props API. Der Begriff Render Prop in React bezieht sich auf eine Technik zum Teilen von Code zwischen React-Komponenten unter Verwendung einer Prop, deren Wert eine Funktion ist. Eine Komponente mit einer Render-Prop nimmt eine Funktion, die ein React-Element zurückgibt und ruft es auf, anstatt ihre eigene Render-Logik zu implementieren.

Die Weitergabe von Daten von einer Komponente an eine untergeordnete Komponente, die die Daten benötigt, kann zu Prop Drilling führen, wenn Komponenten ineinander verschachtelt sind. Dies ist der Vorteil der Verwendung von Context zur gemeinsamen Nutzung von Daten zwischen Komponenten gegenüber der Verwendung der Render-Prop-Methode.

Fazit

In diesem Artikel haben wir eines der fortgeschrittenen Muster von React kennengelernt, nämlich das zusammengesetzte Komponentenmuster. Es ist eine großartige Methode, wiederverwendbare Komponenten in React zu erstellen, indem Sie das zusammengesetzte Komponentenmuster zum Erstellen Ihrer Komponente verwenden und Ihnen viel Flexibilität in Ihrer Komponente bieten. Sie können sich immer noch für die Verwendung von Render Prop entscheiden, wenn Ihre Komponente im Moment keine Flexibilität erfordert.

Zusammengesetzte Komponenten sind am hilfreichsten beim Aufbau von Konstruktionssystemen. Wir haben auch den Prozess der gemeinsamen Nutzung des Zustands innerhalb der Komponenten mithilfe der Kontext-API durchlaufen.

  • Den Code für dieses Tutorial finden Sie auf Codesandbox.