1. Compound Component Pattern
Compound Component Pattern은 여러 개의 하위 컴포넌트들이 하나의 상위 컴포넌트 내에서 작동하도록 설계하는 방식이다.
이 패턴은 하나의 컴포넌트를 여러 하위 컴포넌트들의 조합으로 분리하여 재사용성을 높인다.
Compound Component Pattern 예시
1) Header.jsx (최상위 컴포넌트)
import React from 'react';
const Header = ({ children, ...props }) => {
return <header className="header" {...props}>{children}</header>;
};
Header.Logo = ({ children }) => <div className="logo">{children}</div>;
Header.Navigation = ({ children }) => <nav className="navigation">{children}</nav>;
Header.Search = ({ children }) => <div className="search">{children}</div>;
export default Header;
- Header:
Header는 최상위 컴포넌트로, children을 받아서 그 안에 포함된 Logo, Navigation, Search 컴포넌트를 렌더링한다. - Header.Logo, Header.Navigation, Header.Search:
Header 컴포넌트의 하위 컴포넌트로, Header의 특정 부분을 구성하는 독립적인 요소이다.
2) App.jsx (Header 사용)
import React from 'react';
import Header from './Header';
function App() {
return (
<Header>
<Header.Logo>맥도날드</Header.Logo>
<Header.Navigation>
<ul>
<li>버거</li>
<li>맥런치</li>
<li>맥모닝</li>
</ul>
</Header.Navigation>
<Header.Search>검색</Header.Search>
</Header>
);
}
export default App;
- App.jsx에서는 Header 컴포넌트 하위에 어떤 컴포넌트들이 있는지 쉽게 파악할 수 있다.
- 또한, 필요한 하위 컴포넌트만 골라서 사용할 수도 있다. 예를 들어, 로고와 검색 기능의 표시 여부를 제어해야 하는 경우, 원하는 하위 컴포넌트만 골라서 사용하면 되므로 무분별한 props를 방지할 수 있고 코드의 복잡성을 줄일 수 있다.
- 비록 위 예시는 간단하지만, 공통 컴포넌트를 구현할 때 이 패턴을 활용하면 더 효율적으로 관리할 수 있을 것 같다.
2. HOC(고차 컴포넌트, Higher-Order Component)
Higher-Order Component는 기존의 컴포넌트를 인자로 받아 새로운 컴포넌트를 반환하는 함수이다.
HOC 예시
import React from "react";
import { Redirect } from "react-router-dom";
const withAuth = (WrappedComponent) => {
return (props) => {
const isAuthenticated = Boolean(localStorage.getItem("token"));
if (!isAuthenticated) {
return <Redirect to="/login" />;
}
return <WrappedComponent {...props} />;
};
};
const MyPage = () => <div>My Page</div>;
export default withAuth(MyPage);
- 이처럼 HOC는 동일한 로직을 여러 컴포넌트에 재사용해야 할 때 유용하다.
- 또한, 인증 로직이 변경되더라도 HOC 내부만 수정하면 되므로 유지보수하기 좋다.
3. React Portal
React Portal은 부모 DOM 계층 바깥에 컴포넌트를 렌더링하기 위해 사용된다.
ReactDOM.createPortal(child, container)
- 첫 번째 인자는 부모 DOM 계층 바깥에 렌더링하고 싶은 컴포넌트를 가리키고,
- 두 번째 인자는 이 컴포넌트를 띄울 DOM 엘리먼트를 가리킨다.
React Portal 예시
1) index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>1 to 50</title>
</head>
<body>
<div id="root"></div>
<div id="modal"></div>
</body>
</html>
- 모달이 렌더링 될 위치에 div 엘리먼트를 추가해준다.
2) ModalPortal.jsx
import ReactDom from "react-dom";
const ModalPortal = ({ children }) => {
const el = document.getElementById("modal");
return ReactDom.createPortal(children, el);
};
export default ModalPortal;
- 원하는 컴포넌트를 위에서 추가한 DOM 엘리먼트에 띄우기 위한 포탈을 생성해준다.
3) Game.jsx
import styled from "@emotion/styled";
import ModalPortal from "./ModalPortal";
import AlertModal from "./AlertModal";
const Game = ({ level, startGame, endGame, finalTime, resetState }) => {
return (
<Container>
{/* 코드 중략 */}
{/* 게임 종료 모달 */}
<ModalPortal>
{isModalOpen && (
<AlertModal
time={finalTime}
onClose={() => {
setIsModalOpen(false);
initGame();
}}
/>
)}
</ModalPortal>
</Container>
);
};
export default Game;
- 띄우고 싶은 모달을 위 코드처럼 ModalPortal로 감싸주면 된다.
'리액트 심화 스터디' 카테고리의 다른 글
[Week 5] SSR과 RSC (2) | 2024.11.26 |
---|---|
🏄♀️ 리심스 4주차 - 컴포넌트 패턴 (2) | 2024.11.19 |
🏄♀️ 리심스 3주차 - 리액트 렌더링 최적화 (2) | 2024.11.12 |
[Week 3] Automatic batching, windowing, useMemo, useCallback (2) | 2024.11.12 |
🏄♀️ 리심스 2주차 - 리액트 렌더링 (2) | 2024.11.05 |