내가 React를 배우기 전 가장 귀찮고 짜증났던 부분이자 React를 배우게 된 계기가 되었던 부분은 바로 반복되는 HTML 구조에 다른 내용을 가지고 있는 list를 하나하나 타이핑하는 것이었다.
이럴 바엔 내용만 넣으면 알맞은 HTML 요소에 내용이 입력된 HTML 코드 덩어리를 return하는 함수를 만들 수 있다면 좋겠다고 생각했다.
물론 바닐라 JS로도 가능한 일이었지만 document.createElement와 elem.appendChild가 끝없는 듯이 반복되는 일이었으며, 이 로직을 만드느니 li태그를 일일이 Copy & Paste하는 게 더 생산성이 높다는 생각에 그러지 않았다.(물론 li태그가 엄청 많다면 로직을 만드는 것이 더 낫다.)
그리고 지금 React로 웹페이지 클론코딩을 하다가 마주친 MenuList 컴포넌트에 이 로직을 구현하기로 했다.
const listArray = ["Reservation", "Rooms", (중략) "About"];
return (
<HeaderList>
{listArray.map(listItem, index) => {
return (
<HeaderListItem key={index}>
{listItem}
</HeaderListItem>
);
}}
</HeaderList>
);
처음은 이렇게 구현했고, 생각한 대로 잘 나와주어서 너무 기뻤다.
그런데 이 녀석 마우스를 hover하면 SubMenu가 나타난다.
listItem안에 list가 들어있고, 그 list의 listItem안에 list가 들어있는 모습이다.
내용을 다 작성하니 116줄의 코드가 나왔고, 이건 JSON파일으로 분리해서 import시키는 게 좋겠다는 생각이 들었다.
//HeaderMenu.json
[
{
"listItem": "Reservation",
"subListItem": [
{
"subListItemTitle": "Room"
},
{
"subListItemTitle": "Dining"
},
{
"subListItemTitle": "Membership"
}
]
},
{
"listItem": "Rooms",
"subListItem": [
{
"subListItemTitle": "Room",
"subListDeps2": ["Superior", "Deluxe", "Premier"]
},
{
"subListItemTitle": "Kids",
"subListDeps2": ["Kids Superior", "Kids Deluxe", "Kids Premier"]
},
{
"subListItemTitle": "Suite",
"subListDeps2": [
"Corner Suite",
"Executive Suite",
"Royal Suite",
"Presidential Suite"
]
}
]
},
{
"listItem": "Dining",
"subListItem": [
{
"subListItemTitle": "Aria"
},
{
"subListItemTitle": "Palais De Chine"
},
{
"subListItemTitle": "Lounge & Bar"
},
{
"subListItemTitle": "Josun Deli"
}
]
},
{
"listItem": "Offers",
"subListItem": [
{
"subListItemTitle": "Package"
},
{
"subListItemTitle": "Event"
}
]
},
{
"listItem": "Meeting & Wedding",
"subListItem": [
{
"subListItemTitle": "Meeting",
"subListDeps2": ["Ballroom", "Meeting Room", "Board Room"]
},
{
"subListItemTitle": "Wedding"
}
]
},
{
"listItem": "Activity"
},
{
"listItem": "Facilites",
"subListItem": [
{
"subListItemTitle": "Heavenly Pool"
},
{
"subListItemTitle": "Fitness"
},
{
"subListItemTitle": "Sauna"
},
{
"subListItemTitle": "Leding Library"
},
{
"subListItemTitle": "Entertainment"
}
]
},
{
"listItem": "About",
"subListItem": [
{
"subListItemTitle": "About us"
},
{
"subListItemTitle": "Josun Junior"
},
{
"subListItemTitle": "Gallery"
}
]
}
]
//Hedaer.js
import listArray from './HeaderMenu.json';
<HeaderList>
{listArray.map((listItem, index) => {
return (
<HeaderListItem key={index} isOn={isOn} id={index}>
<a href="/">
{listItem.listItem}
</a>
<SubMenu>
<SubMenuInner>
<SubMenuTitle>
<strong>{listItem.listItem}</strong>
<a href="/">한 눈에 보기</a>
</SubMenuTitle>
<SubList>
{listItem.subListItem.map((subListItem, index) => {
return (
<SubListItem key={index}>
<a href="/">{subListItem.subListItemTitle}</a>
<SubListDeps2>
{subListItem.subListDeps2.map((subListDeps2Item, index) => {
return (
<SubListDeps2Item key={index}>
<a href="/">{subListDeps2Item}</a>
</SubListDeps2Item>
);
})}
</SubListDeps2>
);
</SubListItem>
);
})}
</SubList>
</SubMenuInner>
</SubMenu>
</HeaderListItem>
);
})}
</HeaderList>
listItem은 map함수로 반복해야하니 모두 array로 저장했다. ul이 세 번 중첩되니 map함수도 세 번 불러와서 listArray를 쪼갰다. 코드는 굉장히 난잡했지만 아무튼 list를 만드는 작업은 자동화에 성공했다.
만들고 보니 SubMenu가 없는 listItem도 있었고, SubMenu의 SubMenu만 없는 listItem도 있었기 때문에 조건문을 사용해서 분기해야 했고, 그 과정에서 SubMenu를 만드는 함수와 SubMenuDeps2를 만드는 함수를 나누어 만들어냈다. 그 결과 가독성도 전보다는 높아졌다.
//Header.js
import listArray from './HeaderMenu.json';
<HeaderList>
{listArray.map((listItem, index) => {
return (
<HeaderListItem key={index} isOn={isOn} id={index}>
<a
href="/"
onMouseEnter={(e) => {
setIsHover(true);
setIsOn(index);
}}
>
{listItem.listItem}
</a>
{subMenuFn(listItem)}
</HeaderListItem>
);
})}
</HeaderList>
const subMenuFn = (listItem) => {
if (listItem.subListItem) {
return (
<SubMenu>
<SubMenuInner>
<SubMenuTitle>
<strong>{listItem.listItem}</strong>
<a href="/">한 눈에 보기</a>
</SubMenuTitle>
<SubList>
{listItem.subListItem.map((subListItem, index) => {
return (
<SubListItem key={index}>
<a href="/">{subListItem.subListItemTitle}</a>
{subListDeps2Fn(subListItem)}
</SubListItem>
);
})}
</SubList>
</SubMenuInner>
</SubMenu>
);
} else {
return null;
}
};
const subListDeps2Fn = (subListItem) => {
if (subListItem.subListDeps2) {
return (
<SubListDeps2>
{subListItem.subListDeps2.map((subListDeps2Item, index) => {
return (
<SubListDeps2Item key={index}>
<a href="/">{subListDeps2Item}</a>
</SubListDeps2Item>
);
})}
</SubListDeps2>
);
} else {
return null;
}
};
사실 JSON파일을 잘 쪼개어서 렌더링 하는 것은 정말 기본적인 것이지만, React없이 웹사이트를 만들 때 너무나 간절했던 기술이기 때문에 코딩하는 동안 굉장히 흥미로웠고 결과물을 보니 기쁘기 그지없었다.
생각해보면 API를 요청했을때 받는 res가 거의 모두 JSON형식이니 JSON파일을 잘 가공하여 렌더링 하는 기술은 앞으로도 자주 사용하게 될 것이다.