[React] 합성 컴포넌트 완전 정복하기

김현수·2024년 2월 28일
0

React

목록 보기
18/29


🖋️ 합성 컴포넌트

Q. 어떻게 컴포넌트의 재사용성을 높일까?

Q. Props Drilling 은 어떻게 방지할까?

Q. 올바른 추상화는 어떻게 하는 것 일까?

Solution => "Compound Component"


  • 설명

@ Sub Components 가 Main Component 내부의 상태를 공유하면서 
  비즈니스 로직과 UI 관련된 부분을 구분하는 React Pattern

@ 여러 개의 작은 컴포넌트들이 각각의 책임을 분담하여
  이를 자유롭게 조합하여 하나의 큰 컴포넌트를 만드는 것

  • 특징

    • Context API

      • 자식 요소들에 State 를 공유
      • Props Drilling 방지
        • 상태를 공유하기 위해 Props 로 전달하지만
          해당 State 가 직접적으로 필요하지 않은
          컴포넌트들도 받는 것을 방지

      • 사용
        부모 컴포넌트 내부의 children들이 공유받도록 구현
        그렇지 않은 값은 각각의 자식 컴포넌트가 Props로 받아서 처리
      • 예시
        • Main : Select
        • Sub : Option

  • 장단점

    • 장점

      • 개발자가 필요로 하는 서브 컴포넌트만 합성 가능
        • 개발자에게 "자율성" 줄 수 있다는 것
        • "Props Drilling 방지"
        • 적절하게 "책임" 분배

    • 단점

      • UI에 대한 자유도가 높아 의도와 다르게 합성 가능
      • JSX 코드 길이가 더 길어질 수 있음


  • Tabs Components 구현하기

    • Context 생성

      import React, { createContext, useState, useContext } from 'react';
      
       const TabsContext = createContext();
      
       const useTabs = () => useContext(TabsContext);
      
       const TabsProvider = ({ children }) => {
         const [activeTab, setActiveTab] = useState(0);
      
         const switchTab = (tabIndex) => {
           setActiveTab(tabIndex);
         };
      
         return (
           <TabsContext.Provider value={{ activeTab, switchTab }}>
             {children}
           </TabsContext.Provider>
         );
       };
      
       export { TabsProvider, useTabs };

    • Tabs 컴포넌트 생성

       const Tabs = ({ children }) => {
         return (
           <TabsProvider>
             {children}
           </TabsProvider>
         );
       };
      
       const TabList = ({ children }) => {
         return <div>{children}</div>;
       };
      
       const Tab = ({ children, index }) => {
         const { activeTab, switchTab } = useTabs();
      
         return (
           <button onClick={() => switchTab(index)} 
             style={{ fontWeight: index === activeTab ? 'bold' : 'normal' }}>
             {children}
           </button>
         );
       };
      
       const TabPanels = ({ children }) => {
         return <div>{children}</div>;
       };
      
       const TabPanel = ({ children, index }) => {
         const { activeTab } = useTabs();
      
         if (index !== activeTab) return null;
         return <div>{children}</div>;
       };
      
      Tabs.TabList = TabList;
      Tabs.Tab = Tab;
      Tabs.TabPanels = TabPanels;
      Tabs.TabPanel = TabPanel;
      
      export default Tabs;

    • Tabs 컴포넌트 사용

      const App = () => {
        return (
          <Tabs>
            <Tabs.TabList>
              <Tabs.Tab index={0}>Tab 1</Tabs.Tab>
              <Tabs.Tab index={1}>Tab 2</Tabs.Tab>
              <Tabs.Tab index={2}>Tab 3</Tabs.Tab>
            </Tabs.TabList>
            <Tabs.TabPanels>
              <Tabs.TabPanel index={0}>Content of Tab Panel 1</Tabs.TabPanel>
              <Tabs.TabPanel index={1}>Content of Tab Panel 2</Tabs.TabPanel>
              <Tabs.TabPanel index={2}>Content of Tab Panel 3</Tabs.TabPanel>
            </Tabs.TabPanels>
          </Tabs>
        );
      };
profile
일단 한다

0개의 댓글