FE/React

[React] 재귀 컴포넌트로 트리 메뉴 만들기(2)

SH_Roh 2022. 12. 26. 01:11
반응형

이전 글

[React] 재귀 컴포넌트로 트리 메뉴 만들기(1)

 


이번에는 접었다 폈다 하는 효과까지해서 트리 메뉴를 완성해보려고 한다.

 

routes/Directory/Child.tsx

import { useState } from 'react'
import { DownArrow } from 'assets/svgs'
import * as Styled from './index.styles'

const Child = ({ child }: Props) => {
  const [isOpened, setIsOpened] = useState(true)

  const handleClick = () => {
    setIsOpened((prev) => !prev)
  }

  // ...

  return (
    <>
      <li>
        <Styled.ChildButton type='button' onClick={handleClick}>
          {child.name}
          <Styled.ButtonArrow isOpened={isOpened}>
            <DownArrow width={18} height={18} fill='#666666' />
          </Styled.ButtonArrow>
        </Styled.ChildButton>
      </li>
      <li>
        <Styled.ChildContainer isOpened={isOpened}>
          {child.type === 'folder' && child.children?.map((c) => <Child key={`${c.id}`} child={c} />)}
        </Styled.ChildContainer>
      </li>
    </>
  )
}

먼저 메뉴가 열렸을 때, 닫혔을 때 상태 관리를 위해 isOpened 상태를 만들어준다. 메뉴 이름을 버튼으로 감싸준 후, 버튼을 클릭할 때마다 isOpened 상태가 바뀔 수 있도록 해준다.

 

버튼과 ul에 isOpened를 넘겨주어 css를 통해 접었다 펴지는 효과를 구현해줄 것이다.

 

routes/Directory/index.styles.ts

import styled, { css } from 'styled-components'

interface IChildContainer {
  isOpened?: boolean
}

interface IButtonArrow {
  isOpened: boolean
}

export const Directory = styled.section`
  padding: 15px 0;
  font-size: 16px;
`

export const ChildContainer = styled.ul<IChildContainer>`
  overflow: hidden;
  margin-left: 10px;
  padding-left: 5px;
  border-left: 1px solid #eeeeee;

  ${({ isOpened }) => {
    if (isOpened !== undefined && !isOpened) {
      return css`
        height: 0px;
      `
    }

    return css`
      height: 100%;
    `
  }}

  li {
    cursor: pointer;
    font-size: 16px;
    line-height: 20px;
  }
`

export const ChildButton = styled.button`
  display: flex;
  align-items: center;
  font-size: 16px;
`

export const ButtonArrow = styled.span<IButtonArrow>`
  display: flex;
  align-items: center;
  transform: ${({ isOpened }) => (isOpened ? 'scaleY(1)' : 'scaleY(-1)')};
`

 

Child 컴포넌트를 감싸는 ChildContainer를 만들어주고 overflow:hidden으로 지정해준다.

isOpened가 true일 경우에는 height가 100%, false일 경우는 height가 0px이 되도록 해서 접었다 펴지는 효과를 만들어주었다.

 

그리고 버튼 안에 있는 화살표 아이콘을 isOpened가 바뀔 때마다 상하반전이 되도록 해준다.

 

반응형