๋๋ง์ React ๊ฐ์๊ฐ ์์๋์๋ค. React ๊ฐ์๋ ์์๋์์ง๋ง ๊ฐ์๋ง๊ณ ๋ ํ ์ผ์ด ๋๋ฌด๋๋ฌด ๋ง์๋ค.
ํ์
์คํฌ๋ฆฝํธ ์คํฐ๋์์ 3์ฃผ์ฐจ Todo List ๊ณผ์ ts ๋ง์ด๊ทธ๋ ์ด์
, Vue ๊ณผ์ ์ฝ๋ ๋ฆฌ๋ทฐ, ๊ฐ์ธ ํฌํธํด๋ฆฌ์ค ์ ๊ฒ ๋ฑ๋ฑ ๋จธ๋ฆฌ๊ฐ ํฐ์ ธ๋๊ฐ ๊ฑฐ ๊ฐ์๋ค.
๊ทธ๋๋ ๋ ์ด์ ์ ๋ฆฌ๋ฅผ ๋ฏธ๋ฃจ๋ฉด ์ ๋ ๊ฒ ๊ฐ์ ํ ์ฃผ ๋์ ๋ฐฐ์ด ๊ฒ ์ค ์ค์ํ ๊ฒ์ ์์ฝํด๋ณด๋ ค๊ณ ํ๋ค.
Storybook ๊ธฐ๋ฐ ์ปดํฌ๋ํธ ๊ฐ๋ฐ
Context API์ ํ์์ฑ
ํด๋ฆฝ๋ณด๋: writeText()
์ปดํฌ๋ํธ์ ๊ตฌํ ๋ฐฉ์์ ๋ํ ์ฌ์กฐ๋ช
์ปดํฌ๋ํธ ์ปจํ ์ด๋์์ Children์ ๋ฐฐ์ด๋ก ๋ฟ๋ ค์ฃผ๊ธฐ
๋ฆฌ์กํธ ๊ฐ์์์ ๊ฐ์ฅ ์๋กญ๊ฒ ์๊ฒ ๋์๊ณ ์ ์ ํ๋ ๊ฒ์ด ๋ฐ๋ก Storybook์ด์๋ค.
์ด์ ์ ๋ฆฌ์กํธ๋ฅผ ํด๋ก ์ฝ๋ฉ์ ํตํด ๊ฒํฅ๊ธฐ์์ผ๋ก ๋ฐฐ์ ์ ๋๋ ๋น์ฅ useEffect๋ Redux ๊ฐ์ ๋ด์ฅ ํจ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง ๊ณต๋ถํ์์ง React๋ฅผ ์ฌ์ฉํด ๊ฐ๋ฐํ ๋ ์ด๋ ํ ๋ฐฉ์์ผ๋ก ๊ฐ๋ฐํ ์ง์ ๋ํด์๋ ๋ฃ๋๋ณด๋ ๋ชปํ์๋ค.
ํ์ง๋ง ์ด Storybook์ ์ปดํฌ๋ํธ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ๋ฐํ๋ React์ ๋ํด์ ๋
๋ฆฝ์ ์ธ UI ๊ฐ๋ฐ ํ๊ฒฝ์ ์ ๊ณตํ๋ค.
๋ด๊ฐ ๋ง๋ ๋๋ ๋๋ฃ๊ฐ ๋ง๋ ์ปดํฌ๋ํธ์ UI์ ํด๋น ๋์์ ๋ฐ๋ก ํ์ธํ ์ ์๋ ์ผ์ข
์ ๊ฐ์ด๋๋ถ ์ญํ ์ ํ๋ค.
์๊ฐ๋ณด๋ค ๊ณต์๋ฌธ์๊ฐ ์ข ๋ถ์น์ ํด์ ๊ฐ์ฌ๋์ด ์คํ ๋ฆฌ๋ถ์์ ์ปดํฌ๋ํธ์ arguments ๋ค์ ๊ธฐ๋ณธ๊ฐ๊ณผ ์ปจํธ๋กค ๋ฐฉ์์ ์ง์ ํ๋ ์ฝ๋๊ฐ ํ์ฌ ๋ฒ์ ๊ณผ ๋ง์ง ์์ ์ฐพ๋๋ฐ ๊ณ ์ํ๋ค.
// ๊ฐ์ฌ๋์ defaultValue๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ๋ค.
// ํ์ง๋ง ์ด๊ฒ์ ํ์ฌ ๋ฒ์ (6.3)์์๋ ๊ธฐ๋ณธ๊ฐ์ ๋ํ ์ถ๋ก ์ด ๋์ง ์์ผ๋ฉด ์๋์ผ๋ก undefined๋ก ์ ์ํ๋ฏ๋ก args๋ฅผ ํตํด ๋ฐ๋ก ์ง์ ํด์ฃผ์ด์ผ ํ๋ค.
argsTypes: {
size: {
defaultValue: 10,
control: { type: 'range', min: 1, max: 20 },
}
}
// ํ์ฌ ๋ฒ์ (6.3)์์์ ๋ฐฉ๋ฒ
args: {
size: 10,
},
argsTypes: {
size: {
control: { type: 'range', min: 1, max: 20 },
}
}
storybook์ ๋ํด์ ์ง์ง ์ฒ์ ์ ํด๋ณด์๊ธฐ์ ์ด๊ฒ์ ์ ๋ง ํ์ ์์๋ ์ฌ์ฉํ๋ ๊ฐ์ ์๋ฌธ์ ํ์์๋ค.
ํ์ง๋ง ์ธํฌ ๋ฉํ ๋๊ป ์ง๋ฌธ๋๋ ธ์ ๋์๋ storybook์ ๋ง์ด ์ฌ์ฉํ๋ค๋ ๋ง์์ ํด์ฃผ์ จ๊ณ ์ค์ ๋ก ์ค์ต์ ํ๋ฉด์ ์งํํด๋ณด๋ ํ์ ์ ํ ๋ ํ์ ๊ฐ์ ์ปดํฌ๋ํธ์ ๋ํ ๊ณต์ ๋ฅผ ํ ๋ ํ๋์ ์๊ฐ์ ์ผ๋ก ๋ณผ ์ ์์ด ์ข๋ค๊ณ ๋๊ผ๋ค.
๋จ, React์์ ์์ฑํ ์ปดํฌ๋ํธ๋ฅผ Storybook์ผ๋ก ํ์ํ๊ธฐ ์ํด์๋ ํด๋น ๋ฌธ๋ฒ์ ์ ํ์
ํด์ผ ํ๋ฏ๋ก ์ง์
์ฅ๋ฒฝ์ด ์๋ค๋ ๊ฒ์ด ์ข ํ ์ด์๋ค.
๋ํ ์ปดํฌ๋ํธ์ ๋ง์ props๊ฐ ์์ด ์ฝ๋๊ฐ ๋ณต์กํ๋ฉด ์ด๋ฅผ storybook์ผ๋ก ์ฎ๊ธฐ๋ ๊ฒ๋ ์ด๋ ค์ ๊ธฐ์ React์์ ์ปดํฌ๋ํธ ๊ตฌํ ์ฝ๋๊ฐ ์ ๋ง ์ค์ํ๋ค๋ ๊ฒ์ ๊นจ๋ฌ์๋ค.
2์ฃผ ํ ํํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ ํ ๋ฒ ๊ธฐ์ฉ์ ๊ณ ๋ คํด๋ณผ๋งํ ๊ฐ๋ฐํ๊ฒฝ ํด์ด๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์ปดํฌ๋ํธ๋ค์ ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ์ด๋ฃจ์ด์ ธ ์๋ค.
์ธ์ ํด ์๋ ์ปดํฌ๋ํธ ๊ฐ์ props๋ฅผ ์ ๋ฌํ๋ ๊ฒ์ ์ฝ๋ค.
ํ์ง๋ง ์ปดํฌ๋ํธ์ ๊ตฌ์กฐ์ ๊ฑฐ๋ฆฌ๊ฐ ๋ฉ๋ค๋ฉด? ๋จ๊ณ์ ์ผ๋ก ํ๊ณ ํ๊ณ ๋ค์ด๊ฐ์ผ ํ๋ฏ๋ก ๋ก์ง์ด ๋ณต์กํด์ง๋ค. ์ด ํ์์ Prop Drilling ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
๋ฐ๋ผ์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด React์์๋ Redux, Recoil, Mobx, Context API ๋ฑ ๋ค์ํ ๋ฐฉ๋ฒ์ด ์๋ค.
์ผ๋จ ๊ธฐ์ด๊ฐ ์ค์ํ๋ React์์ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณต๋๋ Context API์ ๋ํด ๋ฐฐ์ฐ๊ณ ์์๋ณด์๋ค.
๊ธฐ๋ณธ์ ์ธ ๋ก์ง์ Context Provider๊ฐ ์ ๊ณต(Provide)ํด์ผํ props๋ฅผ ์ ๋ฌ๋ฐ์
Context Consumer๊ฐ ํด๋น props๋ฅผ ์ ๋ฌ๋ฐ์ ์ฌ์ฉ(Consume)ํ๋ค.
props๋ฅผ ์์ ์์ฌ๋ก ์ ๋ฌํ ์ ์๋ ์ฅ์ ๋๋ฌธ์ ์ ์ฉํ๋ค๊ฐ ๋ง ์ฌ์ฉํ๊ฒ ๋๋ฉด ์ฑ๋ฅ ์ด์๊ฐ ์๊ธธ ์ ์๋ค. ๋ญ๋ ๊ณผ์ ๋ถ๊ธ!
๊ผญ ํ์ํ ์ง์ ์๋ง ์ฌ์ฉํ์.
๋ํ Cosumer๋ ๋ฐ๋์ Provider์ ๋์์ ์กด์ฌํด์ผํ๋ฏ๋ก ์ปดํฌ๋ํธ์ ๋ ๋ฆฝ์ฑ์ ํด์น ์ ์๋ค. ๊ทธ๋์ ๋๋์ฑ ์ฌ์ฉ์ ์ฃผ์๋ฅผ ๊ธฐํด์ผ ํ๋ค.
์ด๋ชจ์ง ๊ฒ์ ํ์ด์ง ์ค์ต ์ค ์ด๋ชจ์ง ๋ฆฌ์คํธ item์ ํด๋ฆญํ์ ๋ ํด๋น item์ ์๋ ์ด๋ชจ์ง ์ฌ๋ณผ์ ๋ณต์ฌํ๋ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค.
์ด ๋ ์ฐ์ธ ๊ฒ์ด clipboard ์ธํฐํ์ด์ค์ wirteText()
๋ฉ์๋์ด๋ค.
// navigator.clipboard ์ ์ ๊ทผํด ์ง์ ๋ emoji.symbol ํ
์คํธ ๋ฌธ์์ด์ ์ปดํจํฐ ํด๋ฆฝ๋ณด๋์ ์ ์ฅํ๋ค.
// ๊ทธ๋ฆฌ๊ณ ctrl+v๋ก ๋ถ์ฌ๋ฃ๊ธฐ๋ฅผ ์คํํ๋ฉด ํด๋น ์ด๋ชจ์ง ์ฌ๋ณผ์ด ๋ถ๋ฌ์์ง๋ค.
<ListItem onClick={() => navigator.clipboard.writeText(emoji.symbol)}>
์ด๊ฒ์ ํตํด ํด๋ฆฝ๋ณด๋์ ์ ์ฅํ ์์๋ฅผ ์ง์ ์ง์ ํ ์ ์์ผ๋ ๋ณต์ฌ ๊ธฐ๋ฅ์ ๊ตฌํํ ๋ ์ ์ฉํ ๊ฑฐ ๊ฐ๋ค.
React๋ฅผ ์ ๋ค๋ฃจ๊ธฐ ์ํด์๋ ์ด๋ป๊ฒ ์ปดํฌ๋ํธํ๋ฅผ ํ ์ง์ ๋ํ ๊ณ ๋ฏผ์ ๋ง์ด ํด์ผํ ๊ฒ ๊ฐ๋ค.
์ค์ต์ ํตํด ๊ฑฐ์ 20๊ฐ ์ ๋์ ๋ฌํ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด๋ณด๋ฉด์ ๋๋ ์ ์
๊ฐ๋จํ Slider(๋ณผ๋ฅจ ์กฐ์ ๋ฐ)๋ Badge๋ฅผ ๋ง๋ค ๋์๋
- ์ด๋ ํ ์์ฑ์ด๋ ์ต์ ์ props๋ก ์ค์ ํด์ฃผ์ด์ผ ํ๋์ง
- ๊ธฐ๋ฅ ๊ตฌํ์ ์ํด ๊ฐ ์์๋ค์ ์ด๋ป๊ฒ ์ธ๋ถํํ ์ง
์ด ๋ ๊ฐ์ง๋ฅผ ๊ณ ๋ คํด์ ๋ง๋ค์ด์ผ ์ฌ์ฌ์ฉ์ฑ์ด ๋ณด์ฅ๋๋ ์ข์ ์ปดํฌ๋ํธ๊ฐ ๋ ์ ์์๋ค.
์๋ฅผ ๋ค๋ฉด Slider ์ปดํฌ๋ํธ ๊ฐ์ ๊ฒฝ์ฐ์๋
์ฌ์ฉ์๊ฐ ์ก๊ณ ์กฐ์ ํ๋ ์์ก์ด๋ Handle, ์ ์ฒด ๋ง๋๊ฐ Rail, ์ ํจํ Rail ๋ฒ์๋ฅผ Track์ผ๋ก ๋๋๋ค.
์ด๊ฒ๋ค์ ๋ถ๋ฆฌํ์ฌ handle์ MouseEvent๋ฅผ ์ถ์ ํ์ฌ Track์ width๋ฅผ ๊ณ์ฐ๋๊ฒ ๊ตฌํํ๋ค.
๊ฐ๋จํ ๊ฐ์ ์กฐ์ ํ๋ ๋ง๋๋ฅผ ๊ตฌํํ๊ธฐ ์ํด์ ์ด๊ฒ์ ๋ ๊ธฐ๋ฅ ๋๋ ๋ฐ์ดํฐ, ์ต์ ์ ๋ฐ๋ผ ์ธ๋ถํํ๋ ์์ด๋์ด๋ ์ผ์ค๊ฐ ์ ๋ง ์ค์ํ๋ค๋ ๊ฒ์ ๊นจ๋ฌ์๋ค.
Breadcrumb์ด๋ Tab ์ปดํฌ๋ํธ ๊ฐ์ ๊ฒฝ์ฐ์๋ ํด๋น item๋ค์ ๋ด๋ Container์ ๋ฌด์ํ ๋ง์ item ๋ค์ด ์ปดํฌ๋ํธ๋ก ๋ค์ด์ฌ ์ ์๋ค.
ํ์ง๋ง ์ด๊ฒ์ ์ผ๋ฐํํ์ฌ props๋ก ๋ฐ์ children ์ปดํฌ๋ํธ ์์๋ฅผ ๋ฐฐ์ด๋ก ๋ณํํ ๋ค ๋ค์ ์ํ๋ Container์ children ์์์ ๋ฟ๋ ค์ฃผ๊ธฐ ์ํด์๋ ํน์ ๋ก์ง์ด ํ์ํ๋ค.
๋ค์์ Breadcrumb ์ปดํฌ๋ํธ ์ฝ๋์ด๋ค.
const Breadcrumb = ({ children, ...props }) => {
const items = React.Children.toArray(children)
// React.Children.toArray๋ก props๋ก ๋ฐ์ children ์์๋ฅผ ๋ฐฐ์ดํํ๋ค.
// ๋ฐฐ์ดํ ํ children์ด BreadcrumbItem ์ปดํฌ๋ํธ๋ก๋ถํฐ ์๋์ง filterํ๋ค.
.filter((element) => {
if (
React.isValidElement(element) &&
element.props.__TYPE === 'BreadcrumbItem'
) {
return true;
}
console.warn("Only accepts Breadcrumb.Item as it's children.");
return false;
})
// filterํ ์์๋ค์ ๋ค์ cloneElement ๋ฉ์๋๋ฅผ ํตํด props๋ฅผ ๋ถ์ฌํด์ ์ปดํฌ๋ํธํํ๋ค.
.map((element, index, elements) => {
return React.cloneElement(element, {
...element.props,
active: index === elements.length - 1,
});
});
return <BreadcrumbContainer>{items}</BreadcrumbContainer>;
};
isValidElement
, cloneElement
, React.Children.toArray
๋ฉ์๋์ ๋ํด์ ์ฒ์์ด์๊ธฐ์ ๋ฌด์จ ์๋ฆฐ๊ณ ํ๋ค.
ํ์ง๋ง ๋ค์์ ์ปดํฌ๋ํธ๊ฐ ๋ค์ด์ฌ ์ ์๋ ์ปดํฌ๋ํธ์ ๋ฌถ์์ ๋ค์ ์ปดํฌ๋ํธํํ ๋๋
- ์ํ๋ ์ปดํฌ๋ํธ์ธ์ง ํ์ธํ ๋ค
- ๋ฐฐ์ด ์์์ props๋ฅผ ๋ถ์ฌํด์ ๋ค์ React ์ปดํฌ๋ํธ๋ก cloneํ์ฌ ๋งคํ
์ด ๋๊ฐ์ง ๋ก์ง์ผ๋ก ๊ตฌํ ๊ฐ๋ฅํ ๊ฒ์ ๊นจ๋ฌ์๋ค.
์ ํ๋์ React ๊ฐ์๋ ๋ญ๊ฐ ์์ฒญ ํจ์ถ์ ์ด๋ค. ๋ ๋ฒจ์ด ์ด์ฌ์๊ฐ ์๋ ์ด๋์ ๋ ์ค์๊ธ์ ๊ธฐ์ค์ ๋ง์ถฐ์ ธ ์๋ค.
๊ฐ์ ๋ฌ๋ ํ์์ 10~15๋ถ์ด์ง๋ง ๊ถ์ฅ ํ์ต ์๊ฐ์ 50๋ถ์ผ๋ก ์ง์ ๋์ด ์๋ ์ด์ ๋ฅผ ์๊ฒ ๋ค. ๋จ์ํ HRD-net ์๊ฐ ์ฑ์ฐ๊ธฐ ์ฉ๋๊ฐ ์๋๋ผ ์ ๋ง ์ถ๊ฐ์ ์ธ ์๊ฐ ํ์ต์ด ํ์ํ๋ค.
ํ์ง๋ง ๋๋ ์คํ๋ ค ์ข๋ค. ๋ ์คํด๋ฝ์ ํตํด React ๊ณต์๋ฌธ์๋ฅผ ์ ๋ ํ๊ธฐ๋ก ํ์๊ณ ์ ํ๋ ๊ฐ์๋ฅผ ํตํด ํด๋น ๊ฐ๋ ์ ๋ํ ์ดํด๊ฐ ๋ถ์กฑํ๋ค๋ ๋ฉํ์ธ์ง๋ฅผ ๋๋ ๋๋ง๋ค ๊ด๋ จ ๋ด์ฉ์ ๊ณต์๋ฌธ์์์ ์ฐพ์ ์ฝ์ด๋ณด๋ ์๊ฐ์ ์์ฒญ ๊ฑธ๋ฆฌ์ง๋ง ์ฐจ๊ทผ์ฐจ๊ทผ ๋ค์ ๊ณต๋ถํ๋ ๊ฒ ๊ฐ์ ์ข๋ค.
๊ฐ์ ์ด์ธ ํ ์ด ํ๋ก์ ํธ, ๊ณง ์์ React ๊ณผ์ , ํ์ ์คํฌ๋ฆฝํธ ์คํฐ๋ ๋ฑ์ผ๋ก ์ธํด ๊ฐ์๊ฐ ์กฐ๊ธ์ฉ ๋ฐ๋ฆฌ๊ธฐ๋ ํ๊ฒ ์ง๋ง ์ด๋ ๊ฒ ์ด์ฌ์์ง ์๊ณ ๊ธฐ์ด(๊ณต์๋ฌธ์ = ๊ต๊ณผ์)๋ฅผ ๋ค์ง๋ฉด์ React๋ฅผ ์กฐ๊ธ์ฉ ๊นจ๋ฌ์๋๊ฐ๋ณด๋๋ก ํ์.
React๋ ํธ๋ ๋์ด์ ํ์ ๊ธฐ์ ์ญ๋์ด๊ธฐ์ ๊ณต์๋ฌธ์ ๊ธฐ๋ฐ์ผ๋ก ๋ค์ ธ๋๊ฐ๊ณ ์๋ค. ์๊ฐ์ ํฌ์ํ๋งํผ React ์ญ๋๋ ์ฑ์ฅํด๋๊ฐ๋ฉด ์ข๊ฒ ๋ค.
์๊ฐ์ด ์ง์ง ๋๋ฌด๋๋ฌด ๋ถ์กฑํ๋ค. ํ์ง๋ง ์ธ์ ๊น์ง ํ๊ณ๋ฅผ ๋ ์ ์๋ ๋ฒ... ๋ ๋ ์์ ๋ ์ต๋ํ ์ง์คํ๊ณ ํ๋์ฉ ํ๋์ฉ ํด๋ณด์..
๋ง์ ๊ฐ์๋ฅผ ๋ค์ด๋ ์ง์ ๋ด๊ฐ ๋ด ์ฝ๋๋ฅผ ์ ์ณ๋ณด๋ฉด ๋ง์งฑ ๋๋ฃจ๋ฌต์ผ ๊ฑฐ ๊ฐ๋ค. ๊ฐ์ธ ํ๋ก์ ํธ๋ฅผ React+ts๋ก ํ๊ธฐ๋ก ํ์ผ๋ ์ฉ์๋ฌด๋ผ๋ ๋ฒ ์ด๋ณด์. ๋ฅ๋ค์ด๋ธ๋ ๊ผญ ํด๋ณด์ ์ด๋ฒ์!!
2์ฐจ ํ ์ดํ ์คํ๋ผ์ธ ๋ชจ์์ด ํ์ ์คํฌ๋ฆฝํธ ์คํ๋์๊ณผ ์ ์ฒด ์คํ๋ผ์ธ ๋ชจ๊ฐ์ฝ ์ผ์ ์ด ์กํ๋ค. ์จ๋ผ์ธ์ผ๋ก ๋ณด๋ ํ๋กฑ์ด๋ค์ ๋ง๋๋ค๋ ์์ฐจ๊ณ ์ ์ตํ ์๊ฐ์ด ๋๊ธธ ๊ธฐ์ํ๋ฉฐ ์ค๋๋ ๋ฌ๋ ค๋ณด์๊ณ
๐ ํด๋น ๋ด์ฉ์ ๊ณต๋ถํ๋ฉด์ ์ ๋ฆฌํ ๊ธ์ ๋๋ค. ํ๋ฆฐ ๋ถ๋ถ์ด๋ ์คํดํ๊ณ ์๋ ๋ถ๋ถ์ด ์๋ค๋ฉด ํผ๋๋ฐฑ ๋ถํ๋๋ฆฝ๋๋ค.