[React] tab menu 구현하기

바질·2022년 9월 30일
0

react-tabmenu

목록 보기
1/1

사용하는 것
react.js, styled-components, typescript, framer-motion

tab menu를 만드는 것은 전에 작성했던 accordion menu와 동일한 방법이다. 순서를 따지자면 tab menu를 만들고 아하~! 했던 것인데 게시글은 accordion을 먼저 썼네...

여기서 framer-motion을 모르는 사람이 있을 거 같아 사이트 주소를 같이 남겨두겠다. 리액트에서 애니메이션을 사용하는 것은 제약이 많지만 해당 라이브러리를 사용하면 만족스러운 애니메이션을 만들 수 있다.

다들 많이 사용해줬으면 좋겠다. 구글링 해도 많이 나왔으면 한다...~~
~~

<Contents bgColor={tab.color}>
   {aboutArray?.map((item: IAbout) => (
      <Content
         onClick={() => setTab(item)}
         className={item === tab ? "selected" : ""}
      >
      {item.title}
      </Content>
   ))}
</Contents>

accordion menu 게시글을 보고 온 사람이면 익숙한 구조일 것이다. 다른 점은 tab menu에서는 animation을 사용한다는 점, li의 height 늘어나지 않고 선택한 contents의 내용을 보여준다는 점이다.

여기서도 내부 내용은 별도로 빼주었다. (컴포넌트로는 빼지 않았다.)
즉, 클릭할 메뉴와 내부 내용을 각각 div로 뺐다는 이야기다.

 <AnimatePresence exitBeforeEnter>
    <div style={{ position: "relative" }}>
      {tab ? (
        <div style={{ position: "absolute", width: "1300px" }}>
           <Inner
             key={tab.title}
             bgColor={tab.color}
             initial={{ opacity: 0, height: 0 }}
             animate={{ opacity: 1, height: "500px" }}
             exit={{ height: 0, opacity: 0 }}
             transition={{
             duration: 0.5,
               type: "tween",
               staggerChildren: 2,
             }}
           >
             <motion.div
               initial={{ opacity: 0 }}
               animate={{ opacity: 1 }}
               exit={{ opacity: 0 }}
             >
             <Title>{tab.title}</Title>
             <TextBox>
               {tab.text.map((item) => (
                  <p>{item.innerText}</p>
               ))}
             </TextBox>
           </motion.div>
         </Inner>
       </div>
      ) : null}
   </div>
</AnimatePresence>

애니메이션을 제외하고 설명하자면,

클릭한 contents를 useState에 담고, state의 값을 가져와 보여준다.
초기값은 언제나 contents index 0번이다. 그렇게 해야 페이지를 열었을 때, 제일 첫 번째의 contents를 보여줄 수 있다.

위의 코드를 보면 selected를 사용한 것을 알 수 있는데, 여기서는 클릭한 menu가 어떤 것인지 알려주기 위해 css를 설정한 것이니 필요 없다면 빼도 된다.

사실 애니메이션이 없어도 tab menu를 구현할 수 있지만 매끄러운 동작도 보기 좋은 UI라고 생각한다. 그러니 간단하게 코드에 나와있는 frame-motion을 설명해보겠다.
필요 없는 사람은 뒤로가기 버튼 클릭!!

frame-motion 설명

<AnimatePresence> </AnimatePresence> 
  • animatepresence 안에 애니메이션을 실행할 html(styled-components)을 넣어야 한다. 넣어주지 않으면 실행하지 않음.
  • react에서는 조건 렌더링을 사용할 수 있어서 {} 를 많이 사용하는데, {} 안에 넣으면 안 된다.
    ex. {isTrue ? <motion.p></motion.p> : null} 이건 안 된다는 뜻이다.

위를 보면 알겠지만 단순히 html 태그를 사용하지 않았다. 앞에 motion이 붙는다. <motion.(html 태그)> 라고 꼭 적어주자. 안 그러면, animation을 실행할 때 에러가 난다.

initial={{ 초기값 }}
animate={{ 초기값에서 변할 값, 최종적인 값을 적어준다. }}

exit가 없으면 animate에서 끝이 난다. exit는 옵션값이니 적지 않아도 상관없으나 exit가 있는 이유는 따로 있다.

exit={{ 사라질 때의 값 }}

exit는 animation이 실행되고 나서 후에 사라질 때 적용되는 값이다.
css의 animation을 생각하고,

initial = 0%
animate = 50%
exit = 100%

이런 식으로 생각하면 안 된다. 약간 다른 의미이다.
exit는 컴포넌트나 html 태그가 사라질 때 적용되는 값이라서 저렇게 생각하고 적으면 exit는 실행되지 않는다. 태그가 사라질 때 적용되는 값!!

transition={{
duration: 0.5,
type: "tween",
staggerChildren: 2,
}}

transition은 css를 아는 사람이라면 알 것이다. frame-motion에서도 똑같다. 태그 안에 별도로 적어주면, 전체적으로 적용되고 개별로 animate 내부에 적어도 괜찮다.

생소한 단어는 staggerChildren이 있겠는데, 이건 아래 자식들의 애니메이션을 지연시키는 옵션이다.
예를 들면,

<motion.div transition={{staggerChildren: 2}}>
	<motion.p />
    <motion.p />
    <motion.p />
    <motion.p />
</motion.div>

이렇게 적었다고 가정해보자. 그러면, 차례대로 애니메이션이 2초씩 지연된다. 첫 번째 자식은 2초, 두 번째 자식은 4초... 이런 식이다. 꽤 유용하니 기억해두는 것도 나쁘지 않다.

내 코드에 나와있는 frame-motion에 대해 설명해보았다, 기회가 된다면 간단한 사용 방법도 블로그에 정리해두는 게 좋다는 생각이 든다.

0개의 댓글