개발/React

[React] 탭 기능 만들기

hr0513 2024. 11. 9. 16:01
728x90
반응형

안녕하세요, hr0513입니다! 😊

 

오늘은 간단한 탭 기능 구현 방법을 공유하려고 합니다.
구현 방식에 대해 의견이나 수정할 부분이 있다면 댓글로 남겨주세요!


1. Tab 컴포넌트

 

먼저 Tab 컴포넌트를 아래와 같이 작성합니다.

tabData라는 props를 받아서 각 탭의 이름과 내용을 구성합니다.

const tabData = [
    { 
      label: '탭 1', 
      content: <div>탭 1에 대한 내용</div> 
    },
    { 
      label: '탭 2', 
      content: <div>탭 2에 대한 내용</div> 
    },
    { 
      label: '탭 3', 
      content: <div>탭 3에 대한 내용</div> 
    },
  ];
  
  ...
  
  <Tab tab={tabData} />

2. useState로 활성 탭 상태 관리하기

 

useState 훅을 사용해 현재 활성화된 탭의 index를 관리합니다.

초기값은 0으로 설정하여 첫 번째 탭을 기본으로 활성화합니다.

const [activeTab, setActiveTab] = useState(0);

3. 탭 클릭 이벤트 핸들러

 

handleTabClick 함수는 탭을 클릭했을 때, 활성화된 탭의 index를 업데이트하는 함수입니다.

const handleTabClick = (index) => {
  setActiveTab(index);
};

4. 탭 기능 구현

 

map 함수를 사용해 tabData 배열을 순회하면서 각 탭 버튼을 렌더링합니다.

현재 활성화된 탭의 index와 activeTab 상태값이 동일할 때, styles.activeTab 스타일이 적용되도록 합니다.

 

return (
    <>
      <div className={styles.tabContainer}>
        <ul className={styles.tabMenu}>
          {tab.map((tab, index) => (
            <li key={index} className={styles.item}>
              <button
                className={`${styles.itemButton} ${index === activeTab ? styles.activeTab : ''}`}
                onClick={() => handleTabClick(index)}
              >
                {tab.label}
              </button>
            </li>
          ))}
        </ul>
      </div>
      
      <div className={styles.contentContainer}>
        {tab[activeTab].content}
      </div>
    </>
  );

 


5. 전체 코드

 

[Tab.jsx]

import { useState } from 'react';
import React from 'react';
import styles from './Tab.module.scss';

const Tab = ({ tab }) => {
  const [activeTab, setActiveTab] = useState(0);

  const handleTabClick = (index) => {
    setActiveTab(index);
  };

  return (
    <>
      <div className={styles.tabContainer}>
        <ul className={styles.tabMenu}>
          {tab.map((tab, index) => (
            <li key={index} className={styles.item}>
              <button
                className={`${styles.itemButton} ${index === activeTab ? styles.activeTab : ''}`}
                onClick={() => handleTabClick(index)}
              >
                {tab.label}
              </button>
            </li>
          ))}
        </ul>
      </div>
      
      <div>
        {tab[activeTab].content}
      </div>
    </>
  );
};

export default Tab;

 

[Tab.module.scss]

.tab {
  &Container {
    position: relative;
    display: flex;
    align-items: center;
    margin-bottom: 30px;

    &:after {
      content: '';
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 1px;
      background: #eaeaea;
    }
  }

  &Menu {
    display: flex;
    overflow: hidden;
    overflow-x: auto;
    flex: 1;

    .item {
      flex: 1;

      &Button {
        position: relative;
        display: flex;
        align-items: center;
        justify-content: center;
        white-space: nowrap;
        width: 100%;
        height: 40px;
        color: #999;
        background: #fff;
        border: transparent;
        font-weight: bold;
        cursor: pointer;
        transition: all ease .2s;

        &:after {
          content: '';
          position: absolute;
          bottom: 0;
          left: 0;
          z-index: 1;
          width: 100%;
          height: 2px;
          background: #009ba5;
          transform: scale(0);
          transition: all ease .2s;
        }

        &.activeTab,
         &:hover {
          color: #009ba5;

          &:after {
            transform: scale(1);
          }
        }
      }
    }
  }
}

6. 실행 화면

728x90
반응형