[React] accordion menu 만들기 -2

바질·2022년 9월 30일
0

react-accordion

목록 보기
1/2

지난 번에 구현했던 acoordion menu를 수정했다.

고치고 싶은 점

지금 상태의 아코디언 메뉴는 선택했을 때 개별적으로 늘어나지만, 하나의 메뉴를 연 상태로 다른 메뉴를 클릭하면 원래 선택했던 메뉴는 닫고 클릭했던 메뉴를 열고 싶다. 이건 나중에 차차 고쳐나가보자.

다른 섹션을 구현하면서 뭔가 이렇게 하면 될 거 같다는 느낌을 받아 다시 도전했다. 고치고 싶은 점은 위와 같고, 택한 방법은 className을 사용하는 것이다.

선택한 menu는 selected라는 className을 붙여주고 선택되지 않은 것들은 붙여주지 않는 걸로.

지난 번에 완성했던 아코디언 메뉴의 구조는 이렇다.

 <Wrapper>
      <Menu contents={contents}></Menu>
      <SectionTitle>Project</SectionTitle>
      <Works>
        <Work className="title">
          <Date>Year</Date>
          <Title>Project title</Title>
          <Produce>Work</Produce>
          <Etc>ETC</Etc>
        </Work>
        <ScrollMenu onWheel={onWheel}>
          {data?.map((project) => (
            <Work onClick={(e) => onShow(e)} key={project.id}>
              <ContentsTitle key={project.title}>
                <div>
                  <Date>{project.date}</Date>
                  <Title>{project.title}</Title>
                  <Produce>{project.work}</Produce>
                  <Etc>{project.etc}</Etc>
                </div>
              </ContentsTitle>
              <ContentsImg key={`${project.title}-image`}></ContentsImg>
              <Over />
            </Work>
          ))}
        </ScrollMenu>
      </Works>
    </Wrapper>

최대한 구조는 건드리지 않고 넘어가고 싶었지만, 이 상태로는 원하는 상태를 구현하지 못할 거 같아 최소한으로 건드렸다.

현재 map으로 li를 만들고 있다. 또한 내부에 해당 데이터를 담을 건데, 이건 별도의 컴포넌트로 빼두었다. 그렇다면, accordion도 컴포넌트로 빼두고, 클릭했을 때 li에 className을 주는 방식으로 가면 어떨까 싶었다.
내부는 어떻게 하든 각자의 자유지만 li를 클릭했을 때의 방식이 중요하다고 느낀다.

바닐라 js로 구현한다면, classList.add와 classList.remove로 해결보면 되는 일이지만, 리액트는 그런 거 없다.
내가 배운 지식에는 없음...

바꾼 코드는 아래와 같으니 참고바란다.

 <Works>
        <Work className="title">
          <div>
            <Date>Year</Date>
            <Title>Project title</Title>
            <Produce>Work</Produce>
            <Etc>ETC</Etc>
          </div>
        </Work>
        {projectData?.map((project) => (
          <Work
            className={project === click ? "selected" : ""}
            key={project.id}
            onClick={() => setClick(project)}
          >
            <Accordion data={project}></Accordion>
          </Work>
        ))}
      </Works>

클릭했을 때 해당 데이터를 useState에 담는다. 물론, 초기값은 데이터의 index 0번이다.

 const [click, setClick] = useState<IProject>(projectData[0]);

그리고 클릭한 값과 map으로 뿌리고 있는 데이터가 같은지 확인하고 같다면, className을 주면 된다. 결과를 보면 내가 원하는 방식으로 작동하는 걸 볼 수 있다...
이렇게 간단한 것을...

어쨌든, 원하는 걸 구현해내서 뿌듯하다. 이거 덕분에 구글링도 많이 했고... 공부도 된 거 같다! 종종 써먹어야지.

참고로 선택했을 때, 열려있는 다른 li가 닫히지 않길 바란다면 위의 방식이 아닌 처음 작성했던대로 구현하고 overflow:scroll을 주면 원활하게 내부 내용을 확인할 수 있다.

0개의 댓글