Componente compuse în reacție
Publicat: 2022-03-10Componentele compuse ajută dezvoltatorii să construiască API-uri mai expresive și mai flexibile pentru a partaja starea și logica în cadrul componentelor. Acest tutorial explică cum se poate realiza acest lucru cu ajutorul utilizării Context API și React pentru a construi componente folosind acest model avansat.
Notă : pentru a putea urmări, veți avea nevoie de o înțelegere de bază a React și a modului în care funcționează API-ul Context.
Ce este o componentă compusă?
Se poate spune că componentele compuse sunt un model care înglobează starea și comportamentul unui grup de componente, dar totuși oferă utilizatorului extern controlul redării părților sale variabile.
Din definiția de mai sus, luând notă de cuvintele cheie: stare și comportament . Acest lucru ne ajută să înțelegem că componenta compusă se ocupă de stare (adică modul în care starea se comportă într-o componentă care este închisă de un utilizator extern fiind părintele componentei).
Obiectivul componentelor compuse este de a oferi un API mai expresiv și mai flexibil pentru comunicarea dintre componentele părinte și cele secundare.
Gândiți-vă la asta ca la etichetele <select>
și <option>
în HTML:
<select> <option value="volvo">Volvo</option> <option value="mercedes">Mercedes</option> <option value="audi">Audi</option> </select>
Eticheta de select
funcționează împreună cu eticheta de option
care este utilizată pentru un meniu derulant pentru a selecta elemente în HTML. Aici <select>
gestionează starea interfeței de utilizare, apoi elementele <option>
sunt configurate pentru modul în care ar trebui să funcționeze <select>
. Componentele compuse din React sunt folosite pentru a construi o componentă declarativă a UI care ajută la evitarea forării prop.
Găurirea elementelor de recuzită transmite elemente de recuzită în mai multe componente secundare. Acesta este, de asemenea, ceea ce ei numesc un „miros de cod”. Cea mai proastă parte a găuririi prop este aceea că, atunci când componenta părinte se redă din nou, componentele secundare vor, de asemenea, redarea din nou și vor provoca un efect de domino asupra componentei. O soluție bună ar fi să folosim API-ul React Context pe care îl vom analiza mai târziu.
Aplicarea componentelor compuse în React
Această secțiune explică pachetele pe care le putem folosi în aplicația noastră, care adoptă modelul de componente compuse ale componentelor de construcție în React. Acest exemplu este o componentă Menu
din pachetul @reach
UI.
import { Menu, MenuList, MenuButton, MenuItem, MenuItems, MenuPopover, MenuLink, } from "@reach/menu-button"; import "@reach/menu-button/styles.css";
Iată o modalitate prin care puteți utiliza componenta Menu
:
function Example() { return ( <Menu> <MenuButton>Actions</MenuButton> <MenuList> <MenuItem>Download</MenuItem> <MenuLink to="view">View</MenuLink> </MenuList> </Menu> ); }
Exemplul de cod de mai sus este una dintre implementările componentelor compuse în care puteți vedea că Menu
, MenuButton
, MenuList
, MenuItem
și MenuLink
au fost toate importate din @reach/menu-button
. Spre deosebire de exportul unei singure componente, ReachUI exportă o componentă părinte, care este Menu
, care însoțește componentele sale secundare, care sunt MenuButton
, MenuList
, MenuItem
și MenuLink
.
Când ar trebui să folosiți componente compuse?
În calitate de dezvoltator React, ar trebui să utilizați componente compuse atunci când doriți:
- Rezolva probleme legate de construirea de componente reutilizabile;
- Dezvoltarea de componente foarte coezive cu cuplare minimă;
- Modalități mai bune de a împărtăși logica între componente.
Avantaje și dezavantaje ale componentelor compuse
O componentă compusă este un model React minunat de adăugat la setul de instrumente pentru dezvoltatori React. În această secțiune, voi prezenta avantajele și dezavantajele utilizării componentelor compuse și ceea ce am învățat din construirea componentelor folosind acest model de dezvoltare.
Pro
Separarea preocupărilor
Având toată logica stării interfeței de utilizator în componenta părinte și comunicarea acesteia pe plan intern tuturor componentelor secundare face o împărțire clară a responsabilităților.Complexitate redusă
Spre deosebire de găurirea suportului pentru a transmite proprietățile către componentele lor specifice, recuzita copii merg la componentele secundare respective folosind modelul de componente compuse.
Contra
Unul dintre dezavantajele majore ale construcției componentelor în React cu modelul componentelor compuse este că numai direct children
componentei părinte vor avea acces la elemente de recuzită, ceea ce înseamnă că nu putem împacheta niciuna dintre aceste componente într-o altă componentă.
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> ); }
O soluție la această problemă ar fi utilizarea modelului de componente compuse flexibile pentru a partaja implicit starea folosind API-ul React.createContext
.
Context API face posibilă trecerea stării React prin componente imbricate atunci când se construiește folosind modelul de componente compuse al componentelor de construcție în React. Acest lucru este posibil deoarece context
oferă o modalitate de a transmite date în arborele componente fără a fi nevoie să transmiteți recuzită manual la fiecare nivel. Folosirea Context API oferă multă flexibilitate utilizatorului final.
Menținerea componentelor compuse în reacție
Componentele compuse oferă o modalitate mai flexibilă de a partaja starea în cadrul aplicațiilor React, astfel încât utilizarea componentelor compuse în aplicațiile React facilitează întreținerea și depanarea efectivă a aplicațiilor.
Construirea unei demonstrații
În acest articol, vom construi o componentă de acordeon în React folosind modelul componentelor compuse. Componenta pe care o vom construi în acest tutorial ar fi o componentă de acordeon personalizată, care este flexibilă și împărtășește starea în cadrul componentei folosind API-ul Context.
Să mergem!
Mai întâi de toate, să creăm o aplicație React utilizând următoarele:
npx create-react-app accordionComponent cd accordionComponent npm start
sau
yarn create react-app accordionComponent cd accordionComponent yarn start
Comenzile de mai sus creează o aplicație React, schimbă directorul în proiectul React și pornește serverul de dezvoltare.
Notă : În acest tutorial, vom folosi styled-components
pentru a ne ajuta să ne stilăm componentele.
Utilizați comanda de mai jos pentru a instala styled-components
:
yarn add styled-components
sau
npm install --save styled-components
În folderul src , creați un folder nou numit componente . Aici ar locui toate componentele noastre. În folderul componente , creați două fișiere noi: accordion.js
și accordion.styles.js
.
Fișierul accordion.styles.js
conține stilul nostru pentru componenta Accordion
(stilizarea noastră a fost realizată folosind styled-components
).
import styled from "styled-components"; export const Container = styled.div` display: flex; border-bottom: 8px solid #222; `;
Mai sus este un exemplu de componente de stil care utilizează biblioteca css-in-js
numită styled-components
.
În fișierul accordion.styles.js
, adăugați stilurile rămase:
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; } `;
Să începem să construim componenta noastră de acordeon. În fișierul accordion.js
, să adăugăm următorul cod:
import React, { useState, useContext, createContext } from "react"; import { Container, Inner, Item, Body, Frame, Title, Header } from "./accordion.styles";
Mai sus, importăm useState
, useContext
și createContext
, care ne vor ajuta să construim componenta acordeonului folosind componente compuse.
Documentația React explică faptul că context
ajută la furnizarea unei modalități de a trece date prin arborele de componente fără a fi nevoie să transmiteți recuzita manual la fiecare nivel.
Privind ceea ce am importat mai devreme în fișierul nostru accordion.js
, veți observa că am importat și stilurile noastre ca componente, ceea ce ne va ajuta să ne construim componentele mai rapid.
Vom merge mai departe și vom crea contextul nostru pentru componenta care va partaja date cu componentele care au nevoie de ele:
const ToggleContext = createContext(); export default function Accordion({ children, ...restProps }) { return ( <Container {...restProps}> <Inner>{children}</Inner> </Container> ); }
Componentele Container
și Inner
din fragmentul de cod de mai sus sunt din fișierul nostru ./accordion.styles.js
în care am creat stiluri pentru componentele noastre folosind componentele cu styled-components
(din biblioteca css-in-js
). Componenta Container
găzduiește întregul Accordion
pe care îl construim folosind componente compuse.
Aici creăm un obiect context folosind metoda createContext()
, așa că atunci când React redă o componentă care se abonează la acest obiect Context, va citi valoarea contextului curent de la furnizorul cel mai apropiat care se potrivește deasupra acestuia în arbore.
Apoi creăm și componenta noastră de bază, care este Acordeonul; este nevoie de children
și orice restProps
. Aceasta este componenta noastră părinte care găzduiește componentele pentru copii ale Acordeonului.
Să creăm alte componente copii în fișierul accordion.js
:
Accordion.Title = function AccordionTitle({ children, ...restProps }) { return <Title {...restProps}>{children}</Title>; }; Accordion.Frame = function AccordionFrame({ children, ...restProps }) { return <Frame {...restProps}>{children}</Frame>; };
Observați .
după componenta părinte Acordeon; aceasta este folosită pentru a conecta componenta copil la componenta părinte.
Hai sa continuăm. Acum adăugați următoarele în fișierul 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> ); };
Așadar, aici creăm o componentă Body
, Header
și Item
care sunt toți copii ai componentei părinte Accordion
. Aici ar putea începe să devină complicat. De asemenea, observați că fiecare componentă copil creată aici primește, de asemenea, o recuzită children
și suporturi de restprops
.
Din componenta Item
element, ne-am inițializat starea utilizând cârligul useState
și am stabilit-o adevărat. Apoi, amintiți-vă, de asemenea, că am creat un ToggleContext
la nivelul superior al fișierului accordion.js
, care este un Context Object
, iar când React redă o componentă care se abonează la acest obiect Context, va citi valoarea contextului curent de la furnizorul care se potrivește cel mai apropiat de deasupra acestuia. în copac.
Fiecare obiect Context vine cu o componentă Provider
React care permite componentelor consumatoare să se aboneze la schimbările de context.
Componenta provider
acceptă o value
prop pentru a fi transmisă componentelor consumatoare care sunt descendenți ai acestui furnizor și aici transmitem valoarea stării curente, care este toggleShow
și metoda pentru a seta valoarea stării curente setToggleShow
. Ele sunt valoarea care determină modul în care obiectul nostru context va împărtăși starea în jurul componentei noastre fără forare de sprijin.
Apoi, în componenta copil header
a Accordion
, distrugem valorile obiectului context, apoi schimbăm starea curentă a toggleShow
la clic. Deci ceea ce încercăm să facem este să ne ascundem sau să ne arătăm acordeonul atunci când faceți clic pe Antet.
În componenta noastră Accordion.Body
, distrugem și toggleShow
, care este starea curentă a componentei, apoi, în funcție de valoarea toggleShow
, putem fie ascunde corpul, fie arăta conținutul componentei Accordion.Body
.
Deci, asta este tot pentru fișierul nostru accordion.js
.
Acum, aici putem vedea cum se reunesc tot ceea ce am învățat despre componentele Context
și Compound components
. Dar înainte de asta, să creăm un nou fișier numit data.json
și să lipim conținutul de mai jos în el:
[ { "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." } ]
Acestea sunt datele cu care vom lucra pentru a testa componenta noastră de acordeon.
Deci hai să continuăm. Am terminat și cred că ați învățat multe urmărind acest articol.
În această secțiune, vom reuni tot ce am lucrat și am învățat despre componentele compuse pentru a le putea folosi în fișierul nostru App.js
pentru a folosi funcția Array.map
pentru a afișa datele pe care le avem deja pe web pagină. De asemenea, observați că nu a existat nicio utilizare a statului în cadrul App.js
; tot ce am făcut a fost să transmitem datele către componentele specifice, iar Context API s-a ocupat de orice altceva.
Acum, la partea finală. În App.js
, faceți următoarele:
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> ); }
În fișierul dvs. App.js , am importat Compound Component Accordion din calea fișierului, apoi am importat și datele noastre false, mapate prin datele false pentru a obține elementele individuale în fișierul nostru de date, apoi le-am afișat în conformitate cu respectivele componentă, de asemenea, ați observa că tot ce trebuia să facem a fost să trecem copiii la componenta respectivă, API-ul Context se ocupă să se asigure că ajunge la componenta potrivită și nu a fost găurit cu prop.
Iată cum ar trebui să arate produsul nostru final:
Alternativă la componentele compuse
O alternativă la utilizarea componentelor compuse ar fi utilizarea API-ului Render Props. Termenul Render Prop în React se referă la o tehnică de partajare a codului între componentele React folosind o prop a cărei valoare este o funcție. O componentă cu un prop de randare ia o funcție care returnează un element React și îl apelează în loc să implementeze propria sa logică de randare.
Pentru a transfera date de la o componentă la o componentă secundară care are nevoie de date, poate duce la forarea de sprijin atunci când aveți componente imbricate unele în altele. Acesta este avantajul utilizării Context pentru a partaja date între componente în comparație cu utilizarea metodei rand prop.
Concluzie
În acest articol, am aflat despre unul dintre modelele avansate ale React, care este modelul de componente compuse. Este o metodă minunată de a construi componente reutilizabile în React, folosind modelul de componente compuse pentru a construi componenta dvs., vă oferă multă flexibilitate în componenta dvs. Puteți alege în continuare să utilizați Render Prop dacă flexibilitatea nu este ceea ce necesită componenta dvs. în acest moment.
Componentele compuse sunt cele mai utile în sistemele de proiectare a clădirilor. De asemenea, am trecut prin procesul de partajare a stării în cadrul componentelor folosind API-ul Context.
- Codul pentru acest tutorial poate fi găsit pe Codesandbox.