React의 복합 구성 요소

게시 됨: 2022-03-10
빠른 요약 ↬ 복합 구성 요소는 UI 구성 요소 간의 관계를 전달하고 명시적 부모-자식 관계를 활용하여 암시적 상태를 공유하는 흥미로운 방법을 사용하는 React의 고급 패턴 중 하나입니다.

복합 구성 요소는 개발자가 구성 요소 내에서 상태와 논리를 공유하기 위해 보다 표현적이고 유연한 API를 구축하는 데 도움이 됩니다. 이 튜토리얼에서는 Context API와 React를 사용하여 이 고급 패턴을 사용하여 구성 요소를 빌드하는 방법을 설명합니다.

참고 : 따라하기 위해서는 React와 Context API가 어떻게 작동하는지에 대한 기본적인 이해가 필요합니다.

복합 성분이란 무엇입니까?

복합 구성 요소는 구성 요소 그룹의 상태와 동작을 포함하지만 여전히 외부 사용자에게 가변 부분의 렌더링 제어를 제공하는 패턴이라고 할 수 있습니다.

위의 정의에서 statebehavior 키워드에 주목하십시오. 이것은 복합 구성 요소가 상태를 처리한다는 것을 이해하는 데 도움이 됩니다(즉, 구성 요소의 부모인 외부 사용자에 의해 둘러싸인 구성 요소 전체에서 상태가 동작하는 방식).

복합 구성 요소의 목적은 상위 구성 요소와 하위 구성 요소 간의 통신을 위해 보다 표현적이고 유연한 API를 제공하는 것입니다.

HTML의 <select><option> 태그처럼 생각하십시오.

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

select 태그는 HTML에서 항목을 선택하기 위한 드롭다운 메뉴에 사용되는 option 태그와 함께 작동합니다. 여기서 <select> 는 UI의 상태를 관리하고 <option> 요소는 <select> 가 작동하는 방식에 대해 구성됩니다. React의 복합 구성 요소는 소품 드릴을 방지하는 데 도움이 되는 선언적 UI 구성 요소를 빌드하는 데 사용됩니다.

소품 드릴은 여러 하위 구성 요소 아래로 소품을 전달합니다. 이것은 또한 그들이 "코드 냄새"라고 부르는 것입니다. 소품 드릴의 최악의 부분은 상위 구성 요소가 다시 렌더링될 때 하위 구성 요소도 다시 렌더링되어 구성 요소에 도미노 효과가 발생한다는 것입니다. 좋은 해결책은 나중에 살펴볼 React Context API를 사용하는 것입니다.

점프 후 더! 아래에서 계속 읽기 ↓

React에서 복합 구성 요소 적용하기

이 섹션에서는 React에서 구성 요소를 구성하는 복합 구성 요소 패턴을 채택하는 응용 프로그램에서 사용할 수 있는 패키지에 대해 설명합니다. 이 예제는 @reach UI 패키지의 Menu 구성 요소입니다.

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

Menu 구성 요소를 사용하는 방법은 다음과 같습니다.

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

위의 예제 코드는 Menu , MenuButton , MenuList , MenuItemMenuLink 가 모두 @reach/menu-button 에서 가져온 것을 볼 수 있는 복합 구성 요소의 구현 중 하나입니다. 단일 구성 요소를 내보내는 것과는 대조적으로 ReachUI는 MenuButton , MenuList , MenuItemMenuLink 자식 구성 요소와 함께 Menu 인 부모 구성 요소를 내보냅니다.

언제 복합 성분을 사용해야 합니까?

React 개발자는 다음을 원할 때 복합 구성 요소를 사용해야 합니다.

  • 재사용 가능한 구성 요소 구축과 관련된 문제를 해결합니다.
  • 최소한의 결합으로 응집력이 높은 부품 개발
  • 구성 요소 간에 논리를 공유하는 더 나은 방법.

복합 구성 요소의 장단점

복합 구성 요소는 React 개발자 툴킷에 추가할 수 있는 멋진 React 패턴입니다. 이 섹션에서는 복합 구성 요소를 사용할 때의 장단점과 이러한 개발 패턴을 사용하여 구성 요소를 구축하면서 배운 내용을 설명하겠습니다.

장점

  • 우려의 분리
    모든 UI 상태 논리를 상위 구성 요소에 갖고 내부적으로 모든 하위 구성 요소와 통신하면 책임을 명확히 구분할 수 있습니다.

  • 복잡성 감소
    속성을 특정 구성 요소로 전달하기 위한 소품 드릴링과 달리 하위 소품은 복합 구성 요소 패턴을 사용하여 해당 하위 구성 요소로 이동합니다.

단점

복합 구성 요소 패턴을 사용하여 React에서 구성 요소를 빌드하는 주요 단점 중 하나는 상위 구성 요소의 direct children 만 props에 액세스할 수 있다는 것입니다. 즉, 이러한 구성 요소를 다른 구성 요소에 래핑할 수 없습니다.

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

이 문제에 대한 해결책은 유연한 복합 구성 요소 패턴을 사용하여 React.createContext API를 사용하여 암시적으로 상태를 공유하는 것입니다.

Context API를 사용하면 React에서 구성 요소를 구성하는 복합 구성 요소 패턴을 사용하여 구성할 때 중첩 구성 요소를 통해 React 상태를 전달할 수 있습니다. 이는 context 가 모든 수준에서 수동으로 props를 전달하지 않고도 구성 요소 트리 아래로 데이터를 전달할 수 있는 방법을 제공하기 때문에 가능합니다. Context API를 사용하면 최종 사용자에게 많은 유연성을 제공합니다.

React에서 복합 구성 요소 유지하기

복합 구성 요소는 React 애플리케이션 내에서 상태를 공유하는 보다 유연한 방법을 제공하므로 React 애플리케이션에서 복합 구성 요소를 사용하면 앱을 더 쉽게 유지 관리하고 실제로 디버그할 수 있습니다.

데모 구축

이 기사에서는 복합 구성 요소 패턴을 사용하여 React에서 아코디언 구성 요소를 빌드할 것입니다. 이 자습서에서 구축할 구성 요소는 Context API를 사용하여 구성 요소 내에서 유연하고 상태를 공유하는 맞춤형 아코디언 구성 요소 입니다.

갑시다!

먼저 다음을 사용하여 React 앱을 만들어 보겠습니다.

 npx create-react-app accordionComponent cd accordionComponent npm start

또는

 yarn create react-app accordionComponent cd accordionComponent yarn start

위의 명령어는 React 앱을 생성하고, 디렉토리를 React 프로젝트로 변경하고, 개발 서버를 시작합니다.

참고 : 이 자습서에서는 구성 요소의 스타일을 지정하는 데 도움이 되는 styled-components 를 사용합니다.

아래 명령을 사용하여 styled-components 를 설치하십시오.

 yarn add styled-components

또는

 npm install --save styled-components

src 폴더에서 components 라는 새 폴더를 만듭니다. 여기에 우리의 모든 구성 요소가 있을 것입니다. 구성 요소 폴더 내에서 accordion.jsaccordion.styles.js 라는 두 개의 새 파일을 만듭니다.

accordion.styles.js 파일에는 Accordion 구성 요소에 대한 스타일이 포함되어 있습니다(스타일 지정은 styled-components 를 사용하여 수행됨).

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

위는 styled-components 라는 css-in-js 라이브러리를 사용하여 구성 요소를 스타일링하는 예입니다.

accordion.styles.js 파일 내에서 나머지 스타일을 추가합니다.

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

아코디언 구성 요소 구축을 시작하겠습니다. accordion.js 파일에 다음 코드를 추가해 보겠습니다.

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

위에서 우리는 복합 구성 요소를 사용하여 아코디언 구성 요소를 빌드하는 데 도움이 되는 useState , useContextcreateContext 후크를 가져옵니다.

React 문서는 context 가 모든 수준에서 수동으로 props를 전달하지 않고도 구성 요소 트리를 통해 데이터를 전달하는 방법을 제공하는 데 도움이 된다고 설명합니다.

accordion.js 파일에서 이전에 가져온 항목을 보면 구성 요소를 더 빠르게 빌드하는 데 도움이 되는 구성 요소로 스타일도 가져왔다는 것을 알 수 있습니다.

계속해서 데이터를 필요로 하는 구성 요소와 데이터를 공유할 구성 요소에 대한 컨텍스트를 만듭니다.

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

위 코드 조각의 ContainerInner 구성 요소는 ./accordion.styles.js 파일에서 가져왔습니다. 여기서 styled-components ( css-in-js 라이브러리에서)를 사용하여 구성 요소에 대한 스타일을 생성했습니다. Container 구성 요소는 복합 구성 요소를 사용하여 구축 중인 전체 Accordion 을 포함합니다.

여기에서 createContext() 메서드를 사용하여 컨텍스트 객체를 생성하므로 React가 이 Context 객체를 구독하는 구성 요소를 렌더링할 때 트리에서 그 위에 가장 근접하게 일치하는 Provider에서 현재 컨텍스트 값을 읽습니다.

그런 다음 Accordion인 기본 구성 요소도 만듭니다. 그것은 children 과 모든 restProps 을 취합니다. 이것은 Accordion의 자식 구성 요소를 포함하는 부모 구성 요소입니다.

accordion.js 파일 내에 다른 자식 구성 요소를 만들어 보겠습니다.

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

주의하십시오 . 부모 Accordion 구성 요소 뒤에; 이것은 자식 구성 요소를 부모 구성 요소에 연결하는 데 사용됩니다.

계속하자. 이제 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> ); };

그래서 여기에서는 모두 부모 구성 요소 Accordion 의 자식인 Body , HeaderItem 구성 요소를 만들고 있습니다. 여기에서 까다로워지기 시작할 수 있습니다. 또한 여기에서 생성된 각 자식 구성 요소는 또한 children prop 및 restprops 를 받습니다.

Item 자식 구성 요소에서 useState 후크를 사용하여 상태를 초기화하고 true로 설정했습니다. 그런 다음 Context Objectaccordion.js 파일의 최상위 수준에서 ToggleContext 를 생성했으며 React가 이 Context 객체를 구독하는 구성 요소를 렌더링할 때 가장 가까운 일치하는 상위 공급자에서 현재 컨텍스트 값을 읽습니다. 나무에서.

모든 Context 개체에는 소비 구성 요소가 컨텍스트 변경 사항을 구독할 수 있도록 하는 Provider React 구성 요소가 함께 제공됩니다.

provider 구성 요소는 이 공급자의 후손인 소비 구성 요소에 전달할 value prop을 수락하며, 여기에서 현재 상태 값인 toggleShow 와 현재 상태 setToggleShow 의 값을 설정하는 메서드를 전달합니다. 컨텍스트 개체가 소품 드릴 없이 구성 요소 주변의 상태를 공유하는 방법을 결정하는 값입니다.

그런 다음 Accordionheader 자식 구성 요소에서 컨텍스트 개체의 값을 파괴한 다음 클릭 시 toggleShow 의 현재 상태를 변경합니다. 그래서 우리가 하려는 것은 헤더를 클릭할 때 아코디언을 숨기거나 표시하는 것입니다.

Accordion.Body 구성 요소에서 구성 요소의 현재 상태인 toggleShow 도 제거한 다음 toggleShow 값에 따라 본문을 숨기거나 Accordion.Body 구성 요소의 내용을 표시할 수 있습니다.

이것이 accordion.js 파일의 전부입니다.

이제 여기에서 ContextCompound components 에 대해 배운 모든 내용이 어떻게 결합되는지 확인할 수 있습니다. 그러나 그 전에 data.json 이라는 새 파일을 만들고 아래 내용을 붙여 넣습니다.

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

이것은 아코디언 구성 요소를 테스트하기 위해 작업할 데이터입니다.

계속 진행하겠습니다. 거의 끝났고 이 기사를 보고 많은 것을 배웠다고 생각합니다.

이 섹션에서는 Array.map 함수를 사용하여 웹에 이미 있는 데이터를 표시하기 위해 App.js 파일에서 사용할 수 있도록 복합 구성 요소에 대해 학습하고 작업한 모든 것을 통합할 것입니다. 페이지. 또한 App.js 내에는 상태가 사용되지 않았습니다. 우리가 한 일은 특정 구성 요소에 데이터를 전달하는 것뿐이었고 Context API가 다른 모든 것을 처리했습니다.

이제 마지막 부분으로 넘어갑니다. App.js 에서 다음을 수행합니다.

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

App.js 파일에서 파일 경로에서 복합 구성 요소 아코디언을 가져온 다음 더미 데이터를 가져오고 더미 데이터를 통해 매핑하여 데이터 파일의 개별 항목을 가져온 다음 각각에 따라 표시했습니다. 또한 우리가 해야 할 일은 해당 구성 요소에 자식을 전달하는 것뿐이었습니다. Context API는 올바른 구성 요소에 도달하고 소품 드릴이 없는지 확인합니다.

최종 제품은 다음과 같아야 합니다.

Accordion 구성 요소의 최종 모습
Accordion 구성 요소의 최종 모습입니다. (큰 미리보기)

복합 구성 요소에 대한 대안

복합 구성 요소를 사용하는 것의 대안은 Render Props API를 사용하는 것입니다. React에서 Render Prop이라는 용어는 값이 함수인 prop을 사용하여 React 구성 요소 간에 코드를 공유하는 기술을 나타냅니다. render prop이 있는 컴포넌트는 자체 렌더 로직을 구현하는 대신 React 요소를 반환하고 호출하는 함수를 사용합니다.

구성 요소에서 데이터를 필요로 하는 하위 구성 요소로 데이터를 전달하려면 구성 요소가 서로 중첩되어 있을 때 드릴 작업을 수행해야 할 수 있습니다. 이는 render prop 메서드를 사용하는 것보다 Context를 사용하여 구성 요소 간에 데이터를 공유하는 이점입니다.

결론

이 기사에서는 React의 고급 패턴 중 하나인 복합 구성 요소 패턴에 대해 배웠습니다. 컴포넌트를 빌드하기 위해 복합 컴포넌트 패턴을 사용하여 React에서 재사용 가능한 컴포넌트를 빌드하는 것은 컴포넌트에서 많은 유연성을 제공하는 멋진 방법입니다. 현재 구성 요소에 필요한 유연성이 아닌 경우 Render Prop을 사용하도록 선택할 수 있습니다.

복합 구성 요소는 설계 시스템을 구축하는 데 가장 유용합니다. 또한 Context API를 사용하여 구성 요소 내에서 상태를 공유하는 과정을 거쳤습니다.

  • 이 튜토리얼의 코드는 Codesandbox에서 찾을 수 있습니다.