React에서 JSON파일을 렌더링

불꽃남자·2020년 9월 7일
1

내가 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가 나타난다.

실제 Rooms메뉴

listItem안에 list가 들어있고, 그 list의 listItem안에 list가 들어있는 모습이다.
내용을 다 작성하니 116줄의 코드가 나왔고, 이건 JSON파일으로 분리해서 import시키는 게 좋겠다는 생각이 들었다.

JSON파일으로 분리

//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파일을 잘 가공하여 렌더링 하는 기술은 앞으로도 자주 사용하게 될 것이다.

profile
프론트엔드 꿈나무, 탐구자.

0개의 댓글