๐ฅ Best Practices of React Compound Components Pattern: Unlock the Full Potential
Let’s improve React Component Design with This Surprisingly Easy Pattern
itnext.io
Compound Component ํจํด์ด๋?
์ปดํ์ด๋ ์ปดํฌ๋ํธ ํจํด(๋ณตํฉ ์ปดํฌ๋ํธ ํจํด)์ ๋ณต์กํ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๊ธฐ ์ํด ์์ ์ปดํฌ๋ํธ๋ค์ ํฉ์ฑํ๋ ๊ฒ
- ๋ด๋ถ์ ์ผ๋ก ์บก์ํ๋ ์ํ๋ฅผ ๊ณต์
- ๋ณดํต ์ปจํ ์คํธ(์ํ)๋ฅผ ๊ฐ์ง ๋ถ๋ชจ ์ปดํฌ๋ํธ, ์ํ๋ฅผ ์ ๊ณต๋ฐ์ ์ฌ์ฉํ๊ณ ์ ๋ฐ์ดํธํ๋ ์์ ์ปดํฌ๋ํธ๋ก ๊ตฌ์ฑ๋จ
<Modal>
<Modal.Header>
Confirm action
</Modal.Header>
<Modal.Body>
Are you sure?
</Modal.Body>
<Modal.Footer>
<button onClick={handleConfirm}>Confirm</button>
</Modal.Footer>
</Modal>
Compound Component ๋ชจ๋ฒ ์ฌ๋ก
๋ชจ๋ฒ ์ฌ๋ก 1:
๋ชจ๋ฒ ์ฌ๋ก 2:
๋ชจ๋ฒ ์ฌ๋ก 3:
๋ชจ๋ฒ ์ฌ๋ก 4:
์ผ๋ถ ์ปดํฌ๋ํธ๊ฐ ์ฌ์ฉ๋์ง ์๊ฑฐ๋ ์๋ชป ํฉ์ฑ๋๋๋ผ๋
์ ์ฒด ์ปดํฌ๋ํธ๊ฐ ์ ๋์ํ๋๋ก ๊ฐ ์ปดํฌ๋ํธ์ ํฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ๊ฐ์ ์ ๊ณตํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
๋ชจ๋ฒ ์ฌ๋ก 5:
props๋ฅผ ํตํด ๋๋ฌด ๋ง์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ์ง ์๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์ด๋ ๊ฒ ํ๋ฉด prop ๋๋ฆด๋ง์ด ๋ฐ์ํ๊ณ ์ฝ๋๋ฅผ ์ ์ง ๊ด๋ฆฌํ๊ธฐ๊ฐ ๋ ์ด๋ ค์์ง ์ ์์ต๋๋ค.
๋์ Redux ๋๋ MobX์ ๊ฐ์ ์ปจํ
์คํธ ๋๋ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ชจ๋ฒ ์ฌ๋ก 6:
์ข ์ข ์ปดํฌ๋ํธ ๊ฐ์ ์ํ๋ฅผ ๊ณต์ ํ๊ธฐ ์ํด React Context API์ ํจ๊ป ์ฌ์ฉ๋ฉ๋๋ค.
๋ชจ๋ฒ ์ฌ๋ก 7:
shouldComponentUpdate, ๋ฉ๋ชจ์ด์ ์ด์
๋๋ ์ฝ๋๋ฅผ ์ต์ ํํ๋ ๊ธฐํ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ
๋ถํ์ํ ๋ ๋๋ง์ ํผํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
๋ชจ๋ฒ ์ฌ๋ก 8:
React Compount Component ํจํด ์ค๊ณ
๋จผ์ ์ปดํฌ๋ํธ์ ์ํ๋ฅผ ํตํฉ๊ด๋ฆฌ(์ค์ผ์คํธ๋ ์ด์ )ํ๋ ์ต์์ ์ปจํ ์คํธ ์ปดํฌ๋ํธ๋ฅผ ์ ์ํฉ๋๋ค.
์ด๋ฅผ ๋ถ๋ชจ ์ปดํฌ๋ํธ๋ผ ํฉ๋๋ค.
๋ณดํต dot syntex๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ์๋์ ๊ฐ์ด ๊ตฌ์ฑํฉ๋๋ค.
const Modal = ({ children }) => {
const childrenArray = React.Children.toArray(children);
const header = childrenArray.find(child => child.type === Modal.Header);
const body = childrenArray.find(child => child.type === Modal.Body);
const footer = childrenArray.find(child => child.type === Modal.Footer);
return (
<div className="modal">
<div className="modal-header">{header}</div>
<div className="modal-body">{body}</div>
<div className="modal-footer">{footer}</div>
</div>
);
};
Modal.Header = ({ children }) => {
return <div className="modal-header">{children}</div>;
};
Modal.Body = ({ children }) => {
return <div className="modal-body">{children}</div>;
};
Modal.Footer = ({ children }) => {
return <div className="modal-footer">{children}</div>;
};
์ด ์์ ์์ Modal ์ปดํฌ๋ํธ๋ Modal.Header, Modal.Body ๋ฐ Modal.Footer ์ธ ๊ฐ์ง ์๋ธ ์ปดํฌ๋ํธ๋ฅผ ์ ์ํฉ๋๋ค.
์ด๋ฌํ ๊ฐ ์๋ธ ์ปดํฌ๋ํธ๋ Modal ์ปดํฌ๋ํธ ๊ฐ์ฒด์ ์์ฑ์ผ๋ก ์ ์๋ฉ๋๋ค.
Modal ์ปดํฌ๋ํธ์ ๋ ๋๋ง ๋ฉ์๋์์
์๋ธ ์ปดํฌ๋ํธ๋ ์ ํ๊ธฐ๋ฒ์ ์ฌ์ฉํ์ฌ ์ก์ธ์คํ๊ณ , ์ปดํฌ๋ํธ์ ์ ์ ํ ์์น์ ๋ ๋๋ง ํฉ๋๋ค.
์ด ํจํด์ ์ฌ์ฉํ๋ฉด ์์ ์ปดํฌ๋ํธ๋ฅผ ์ฝ๊ฒ ์ค์ ํ๊ณ ๋ถ๋ชจ ์ปดํฌ๋ํธ ๋ด์์ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ฆ React ์ฝ๋๋ฅผ ๊ตฌ์กฐํํ๋ ๋ณด๋ค ์ ์ฐํ๊ณ ๋ชจ๋ํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
Context API๋ฅผ ์ฌ์ฉํ์ฌ ๋ณตํฉ ์ปดํฌ๋ํธ ๊ฐ ์ํ ๊ณต์
Context API๋ฅผ ์ฌ์ฉํ๋ฉด
props๋ฅผ ํตํ ์ ๋ฌ ์์ด ์์ ์ปดํฌ๋ํธ ๊ฐ ์ํ ๋๋ ์ ๋ณด๋ฅผ ์ฝ๊ฒ ๊ณต์ ํ ์ ์์ต๋๋ค.
const ModalContext = createContext({});
const Modal = ({ children }) => {
const [isOpened, setIsOpened] = useState(false)
const childrenArray = React.Children.toArray(children);
const header = childrenArray.find(child => child.type === Modal.Header);
const body = childrenArray.find(child => child.type === Modal.Body);
const footer = childrenArray.find(child => child.type === Modal.Footer);
return (
<ModalContext.Provider value={{ isOpened, setIsOpened }}>
<div className="modal">
<div className="modal-header">{header}</div>
<div className="modal-body">{body}</div>
<div className="modal-footer">{footer}</div>
</div>
</ModalContext.Provider>
);
};
Modal.Header = ({ children }) => {
const {setIsOpened} = useContext(ModalContext)
return <div className="modal-header">{children}<button onClick={() => setIsOpened(false)}>X</button></div>;
};
Modal.Body = ({ children }) => {
return <div className="modal-body">{children}</div>;
};
Modal.Footer = ({ children }) => {
const {setIsOpened} = useContext(ModalContext)
return <div className="modal-footer">{children}<button onClick={() => setIsOpened(false)}>Close</button></div>;
};โ
ModalContext๋ createContext()๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑ๋๋ฉฐ
useContext() ํํฌ๋ฅผ ์ฌ์ฉํ์ฌ Modal.Header ๋ฐ Modal.Footer ์ปดํฌ๋ํธ์
isOpened ์ํ ๋ฐ setIsOpened ํจ์๋ฅผ ์ ๊ณตํ๋๋ก ํฉ๋๋ค.
๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ ๋ก์ง๊ณผ ๋ ๋๋ง ๋ ๋ค ์ฒ๋ฆฌํ ์ ์์ด, ๊ด์ฌ์ฌ๊ฐ ์ ๋งคํ ์ ์์ผ๋,
์ต์
๊ณผ ์ํ, ํจ์ ๋ชจ๋ ์ฌ์ฉ์ ์ธํฐ๋์
๊ด์ ์์ ์ค๊ณํ๋ฉด ์ข๋ค.
์ปดํฌ๋ํธ ๊ตฌ์กฐ๋ ์ต๋ํ ์ฌ์ฉ์๊ฐ ๋ณด๋ ๋ชจ์ต์ ๋ฐ์ํ๋ฉด ์ข๋ค.
๋ฆฌ์กํธ๋ฅผ ์ด์ฉํ ํ์ดํธํ
์คํธ(integration, e2e)์์๋ ์ ์ฌํ ๋
ผ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค