Render Props๋ฅผ ํตํ UX ๊ฐ์
์๊ตฌ ์ฌํญ
๊ฐ์ธ ์ค์ ํ์ด์ง๋ฅผ ๋ด๋นํ๊ณ ์๋๋ฐ ๋ชจ๋ฐ์ผ ์ํฉ์์ ๋ชจ๋ฌ์ Drawerํ์์ผ๋ก ๋ฐ๊พธ๋๊ฒ ์ข์ ๊ฒ ๊ฐ๋ค๊ณ ํ์๋ค๊ณผ ํ์๋ฅผ ํตํด ๊ฒฐ๋ก ์ด ๋ฌ์๋ค. ํ์ฌ์ํฉ์ ๋ชจ๋ฐ์ผ ๋ชจ๋ฌ์ ๋ค์๊ณผ ๊ฐ์๋ค
์์ ์ฌ์ง๊ณผ ๊ฐ์ ๋ชจ๋ฌ์ด ์ฌ๋ฌ๊ฐ ์๋๋ฐ ๊ธฐ์กด์๋ ๋ง๊ฐ๊ธฐ๊ฐ์ด ์์ด์ ๊ตฌํํ๋๋ฐ๋ง ์ง์คํ๋ ๋๋จธ์ง ๊ฐ ๋ชจ๋ฌ๋ง๋ค ๊ฐ๊ฐ์ ์ปดํฌ๋ํธ๊ฐ ์์๋ค ์ด๋ฌํ ์ํฉ์ด ๋ฐ์ํ๋๊น ๋ฌธ์ ์ ์ด ๋ชจ๋ฐ์ผ ํ๋ฉด์์ Drawer ๋ชจ๋ฌ์ ๊ตฌํํ๋ ค๊ณ ํ๋ฉด ๊ฐ๊ฐ์ ์ปดํฌ๋ํธ๋ณ๋ก Drawer ํ์์ ๋ชจ๋ฌ์ ๊ตฌํํด์ผํ๋ค.์ด๋ฅผ ํด๊ฒฐํ๊ธฐ์ํด ์ฌ๋ฌ ๋ ํผ๋ฐ์ค๋ฅผ ์ฐพ๋์ค ๋ํ์ ์ธ ํจํด 2๊ฐ์ง๋ฅผ ์ฐพ์๋ค ๋ฐ๋ก ์ปดํ์ด๋ํจํด
๊ณผ render props ํจํด
์ด๋ค. ๋จผ์ ๊ฐ๋จํ ์ค๋ช
์ ์๊ธฐํ๊ณ ํด๊ฒฐ๋ฐฉ๋ฒ์ ์์๋ณด๋๋ก ํ์.
Render Prop ํจํด
Render Prop ํจํด์ด๋
๋ ๋ ํ๋กญ์ ์ปดํฌ๋ํธ์ ํ๋กญ(prop) ์ค ํ๋๋ก, ํจ์ ํํ์ ๊ฐ์ ๊ฐ์ง๋ฉฐ, ์ด ํจ์๋ JSX ์๋ฆฌ๋จผํธ๋ฅผ ๋ฐํํ๋ค. ์ด ์ปดํฌ๋ํธ ์์ฒด๋ ๋ ๋ ํ๋กญ ์ธ์๋ ์๋ฌด๊ฒ๋ ๋ ๋๋งํ์ง ์์ผ๋ฉฐ, ์์ฒด์ ์ธ ๋ ๋๋ง ๋ก์ง์ ๊ตฌํํ๋ ๋์ , ๋จ์ํ ๋ ๋ ํ๋กญ์ ํธ์ถํ์ฌ ๋ ๋๋ง์ ์ํํ๋ค
Render Prop ํจํด ์์ ์ฝ๋
export default function App() {
return (
<div className="App">
<h1>โ๏ธ Temperature Converter ๐</h1>
<Input
render={(value) => (
<>
<Kelvin value={value} />
<Fahrenheit value={value} />
</>
)}
/>
</div>
);
}
์ด์ ๊ฐ์ด ์ฝ๋๋ฅผ ๊ตฌ์ฑํ๋ฉด Input์ปดํฌ๋ํธ๋ Kelvin์ด๋ Fahrenheit๊ฐ์ด ์์ธํ ๋ก์ง์ ๋ชฐ๋ผ๋ ๊ทธ๋ฅ render prop์ ํธ์ถํ๋ฉด ๋๋ค. ์ด๋ก์จ ์ด๋ ํ ํ ๋๋ฉ์ธ์ ์ข ์์ ์ด ์๊ณ ์ฌ์ฌ์ฉ์ฑ ์๊ฒ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๋ค.
Compound ์ปดํฌ๋ํธ ํจํด
Compound(ํฉ์ฑ) ์ปดํฌ๋ํธ ํจํด
์ง์ญ ํ์๋ฉด ์ปดํฌ๋ํธ๋ฅผ ํฉ์ฑ ์ํจ๋ค๋ ๋ป์ด๋ค. ์ด๋ฌํ ํจํด์ ํน์ง์ UI๋ฅผ ์์ ๋กญ๊ฒ ๊ตฌ์ฑํ ์ ์๊ณ ์ ์ธ์ ์ด๋ฏ๋ก ์ดํดํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ์์ฑํ ์ ์๋ค. ๋ํ Props drilling์ ๋ฌธ์ ๋ ํผํ ์ ์๋ค.
Compound ์ปดํฌ๋ํธ ํจํด ์์์ฝ๋
ํ์ฌ ์ฐ๋ฆฌ๊ฐ ์ด์ํ๋ ๋ด์ค๋ ํฐ ๊ด๋ จ ์ฌ์ดํธ์์ ์ฌ์ฉํ๋ ์ปดํ์ด๋ ํจํด ์ผ๋ถ๋ฅผ ์์๋ก ๊ฐ์ ธ์๋ค. ๋ง์ฝ ์ปดํ์ด๋ ํจํด์ด ์์๋ค๋ฉด ์์ ๊ฐ์ prop๋ค์ด ํ ์ปดํฌ๋ํธ ์์ ๋ค์ด๊ฐ์ผ ํ๋ค. ๋ํ ๋ง์ฝ์ ํ๋กํ ์ธ๋ค์ผ์ ์์น๋ฅผ ๋ฐ๊ฟ๋ฌ๋ผ๊ณ ์๊ตฌ์ฌํญ์ ๋ฐ์๋ ์ปดํ์ด๋ ํจํด์ ์ฌ์ฉํ๋ฉด ๊ด์ฌ์ฌ ๋ถ๋ฆฌ๊ฐ ๋์ด์๊ณ ๋ฌด์๋ณด๋ค ์ ์ธ์ ์ด๊ธฐ ๋๋ฌธ์ ArticleCard.NewletterAvtar ์ปดํฌ๋ํธ์ ์ ์ธํ๋ ์์น๋ง ๋ฐ๊พธ๋ฉด ์ ์ฉ์ด ๊ฐ๋ฅํ๋ค ์ด์ฒ๋ผ UI์ ์ค์ ์ ์์ด์๋ ๋๊ฒ ์์ ๋ก์ด ๊ฒ์ ์ ์ ์๋ค.
์ ๊ทผ ๋ฐฉ๋ฒ
์ผ๋จ ๊ด์ฌ์ฌ ๋ถ๋ฆฌ๋ฅผ ์ํด Drawer๋ฅผ ์ ์ฉ์์ผ์ผํ๋ ๋ชจ๋ฌ๋ผ๋ฆฌ ๋น๊ต๋ฅผ ํด์ ๊ณตํต์ ์ ์ฐพ์ผ๋ ค๊ณ ํ๋ค.
์์๊ฐ์ด ๋นจ๊ฐ์ ๋ค๋ชจ ๋ฐ์ค ์์ ์๋ ์์๋ค ๋ง๊ณ ๋ ํ์์ด ๋น์ทํด ๋ณด์๋ค. ๊ทธ๋ ๋ค๋ ๋ป์ ๋ค๋ชจ๋ฐ์ค ์์ ์๋ ์์๋ง ๊ฐ์๋ผ์ธ ์ ์๋ ํ์์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ๋ฉด ํ์ฌ ๋ฐ๋ก ๊ตฌํ๋ 2๊ฐ์ ๋ชจ๋ฌ ์ปดํฌ๋ํธ๋ฅผ ํ๋๋ก ๋ฌถ์์ ์์ ๊ฒ ๊ฐ์๋ค. ๊ทธ๋ ๊ฒ๋๋ฉด ์๊น ๋งจ ์ฒ์์ ๋งํ ๋ฌธ์ ์ํฉ ์ฒ๋ผ Drawer ํ์์ ๋ชจ๋ฌ์ ๋ฐ๋ณต์ ์ผ๋ก ๋ก์ง์ ์์ฑํ ํ์๊ฐ ์๊ฒ ๋๋ค.
์ปดํ์ด๋ ํจํด๊ณผ render Propํจํด์ ์ ํํด์ผํ๋๋ฐ ํ์์ ๊ฒฝ์ฐ Render Propํจํด์ ์ ํ์ ํ๋ค. ์๋ํ๋ฉด ์ผ๋จ ๊ตฌํํ๋ ค๋ ๋ชจ๋ฌ ์์ฒด๋ Props๋ ๋ง์ง ์๊ณ UI๊ด์ ์ผ๋ก ๋ดค์๋๋ ๋ชจ๋ฌ ํน์ฑ์ ๊ฐ ์์๋ค์ ์์น๋ฅผ ๋ฐ๊พธ๊ฑฐ๋ ๊ทธ๋ด ๊ฐ๋ฅ์ฑ์ ์ ์ด๋ณด์ฌ์ UI์ ์์จ์ฑ๋ ๊ทธ๋ ๊ฒ ํ์ํ์ง๋ ์์๋ค. ๊ทธ๋ฆฌ๊ณ ์ปดํ์ด๋ ํจํด์ ์ฌ์ฉํด๋ดค์ง๋ง Render Propsํจํด์ ์ฌ์ฉ์ ์ํด๋ด์ ๊ถ๊ธํ๊ธฐ๋ ํด์ render Props๋ฅผ ์ ํํ๋ค.
ํด๊ฒฐ์ฑ
๊ณตํต๋๋ ๋ถ๋ถ์ ์ฐพ์์ผ๋ SRP(Single Responsibility Principle)์์น์ ๋ฐ๋ผ ๊ด์ฌ์ฌ ๋ณ๋ก ๋ก์ง์ ๋๋๋ฉด ์์ ๊ฐ๋ค. B Component๋ ๊ฐ ๋ชจ๋ฌ๋ณ๋ก ๊ฐ์ธ ์ค์ ์ ํ ๋ ์ ์ ๊ฐ ์ฌ์ฉํ๋ ์ ๋ ฅ๊ฐ์ ๋ฐ๋ ์ปดํฌ๋ํธ๋ค. A Component๋ ๋ชจ๋ฌ ๋ซ๊ธฐ ๊ธฐ๋ฅ๊ณผ ํ์ธ ๋ฒํผ์ ๋๋ ์ ๋ ์ ์ ๊ฐ ์ค์ ํ๋ ๊ฐ์ ์ ๋ฌํด์ฃผ๋ ๋ชจ๋ฌ์ ์ญํ ๋ง ์ํํด์ฃผ๋ฉด๋๋ค.
ํ๋ก์ ํธ ์ฝ๋
//UserSettingModal.tsx
export default function UserSettingModal({
submitHandler,
renderItem,
closeHandler,
title,
isOpen,
}: UserSettingModalType) {
const [postValue, setPostValue] = useState<unknown>()
const { isMobileView } = useCheckDevice()
return isMobileView ? (
<Drawer onSubmit={submitHandler} close={close}>
Drawer ํ์ ๋ชจ๋ฌ ๊ตฌ์กฐ
</Drawer>
) : (
<Modal onSubmit={submitHandler} close={close}>
Drawer ํ์ ๋ชจ๋ฌ ๊ตฌ์กฐ
</Modal>
)
}
//settingPage.tsx
<UserSettingModal
isOpen={isOpen}
title="์ฐ์
๋ถ์ผ ๋ณ๊ฒฝ"
submitHandler={(value: unknown) => {
mutate({ value, type: 'occupation', email: userEmail })
close()
}}
closeHandler={close}
renderItem={(setPostValue) => (
<UserSettingList
listData={USER_INFO_OCCUPATION}
wrap
setPostValue={setPostValue}
initialItem={userProfile?.occupation as string}
/>
)}
/>
renderItem์ props๋ฅผ ํ์ฉํด ๊ฐ์ ํ์ํ ๊ฐ์ธ์ค์ ๊ด๋ จ ์ปดํฌ๋ํธ๋ค์ ๊ฐ์๋ผ์ฐ๋ ํ์์ผ๋ก ์ฌ์ฉํ๋ฉด ๋๋ค. ์ธ์๋ก๋ setPostValue๋ผ๋ setStateAction์ ์ ๋ฌ ํด์ค์ผ๋ก์จ B Component๊ฐ ์ ์ ๊ฐ ์ค์ ํ ๊ฐ์ A Component์๊ฒ ์ ๋ฌํด์ค๋ค. ์ด๋ก์จ state๋ฅผ ๋์ด์ฌ๋ฆฌ์ง ์๊ณ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๊ฒ ๋๋ค.
๋ํ UserSettingModal์ด๋ผ๋ ์ปดํฌ๋ํธ ์ฆ A component๋ฅผ ๋ฐ๋ก ๊ณตํต์ผ๋ก ๋นผ๋์ผ๋ฉด์ Drawerํ์์ ๋ชจ๋ฌ๊ณผ ๊ด๋ จ๋ ์ฝ๋๋ฅผ ๋ฐ๋ณต์ ํผํ ์ ์๊ฒ ๋์๋ค.
์์ฐ ์์
์ถ์ฒ
https://www.patterns.dev/react/compound-pattern
https://velog.io/@yesbb/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%9D%98-%EA%B4%80%EC%A0%90%EC%9C%BC%EB%A1%9C-%EB%B0%94%EB%9D%BC%EB%B3%B8-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EA%B3%A0%EA%B8%89-%ED%8C%A8%ED%84%B4-Compound-component-Render-props#%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EA%B3%A0%EA%B8%89-%ED%8C%A8%ED%84%B41--compound-component-pattern