Zusammengesetzte Komponenten in Reaktion
Veröffentlicht: 2022-03-10Zusammengesetzte 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.
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:
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.