중복되지 않는 tab button 만들기

Wynter24·2023년 9월 22일
0

구현하고자 하는 기능

  • tab 버튼 3개
  • 처음 랜더링이 됐을 때 관광명소 tab이 클릭되 것 처럼 보이게 하기
  • 단일 선택만 가능(중복 선택x)

tab button


코드 살펴보기

// Plan.tsx파일

const categories = ['관광명소', '음식점', '카페'];
const [ activeTab, setActiveTab] = useState<number>(0); // 선택된 탭을 관리하는 상태

<Category>
            {categories.map((item, index) => (
              <PlaceBtn
                key={index}
                title={item}
                onClick={()=>{setActiveTab(index)}}
                active={activeTab === index} // 현재 탭이 활성화된 경우 true, 아닌 경우 false
              />
            ))}
          </Category>

onclick을 했을 때 setActiveTab(index) 실행 = 내가 클릭한 item의 index 값이 activeTab에 저장된다.
내가 클릭한 item의 index 즉 activeTab이 map으로 반복되는 item의 index와 같으면 true가 되어 PlaceBtn.tsx로 전달

처음 화면이 랜더링 되고 보이는 tap은 activeTab의 default 값이 0이므로 categories의 첫번째 요소(관광명소)가 클릭된 것처럼 (그림자가) 보인다.

// PlaceBtn.tsx 파일
export default function PlaceBtn({ title, onClick, active }: PlaceBtnProps) {
  return (
    <ButtonLayout>
      <Btn onClick={onClick} className={active ? 'active' : ''}>
        {title}
      </Btn>
    </ButtonLayout>
  );
}

const Btn = styled.button`
&.active {
    box-shadow: 4px 4px 6px rgba(0, 0, 0, 0.2);
  }
 `

active가 true 일때 className='active'가 되어 그림자가 생긴다.


중복 선택 가능

<Category>
      {categories.map((item) => (
        <PlaceBtn
          key={item}
          title={item}
          active={item === activeTab} // 현재 탭이 활성화된 경우 true, 아닌 경우 false
          onClick={handlePlaceBtnClick} // PlaceBtn이 클릭되었을 때 실행되는 함수
        />
      ))}
</Category>
type PlaceBtnProps = {
  title: string;
  add?: any;
  onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
  active: any;
};

export default function PlaceBtn({ title }: PlaceBtnProps) {
  const [btnShadow, setBtnShadow] = useState(false);

  return (
    <ButtonLayout>
      <Btn onClick={() => setBtnShadow(!btnShadow)} className={btnShadow ? 'active' : ''}>
        {title}
      </Btn>
    </ButtonLayout>
  );
}

고군분투

const [ activeTab, setActiveTab] = useState<string>('관광명소'); // 선택된 탭을 관리하는 상태
// Category - PlaceBtn이 클릭될 때 실행될 함수
const handlePlaceBtnClick = (title: any): any => {
  setActiveTab(title);
};

<Category>
  {categories.map((item) => (
    <PlaceBtn
      key={item}
      title={item}
      active={item === activeTab}
      onClick={handlePlaceBtnClick}
    />
  ))}
</Category>
const [btnShadow, setBtnShadow] = useState(false);

<ButtonLayout>
  <Btn onClick={()=>{setBtnShadow(!btnShadow); onClick(title);}} 
   className={btnShadow && active? 'active' : ''}>
    {title}
  </Btn>
</ButtonLayout>

원래 중복 선택이 가능한 상태에서 단일 선택만 가능하도록 코드를 수정하려고 했는데 생각처럼 잘 동작하지 않아서 몇 시간을 앓았다.

처음에는 title을 비교하여 active에 true값 넘겨 주었다.
title로 비교했을 때 내가 클릭한 title(이름)과 반복되는 이름이 값이 일치하면 true이다. button 컴포넌트에서 클릭 될때마 상태가 바뀌도록 btnShadow라는 state로 관리하였다.

이렇게 했을 때 중복 선택이 되지 않지만 계속 클릭을 하다 어느 순간 부터 두번 클릭을 해야 상태가 바꼈다.
그래서 클릭이 잘 됐는지 확인하기 위해 콘솔로 확인했을 때 모두 잘 출력 되었다. 이는 btnShadow와 관련하여 true/false 값이 꼬였다는 것이다.

클릭할 때마다 btnShadow와 active의 값을 확인했을 때
클릭이 잘 일어나는 3번은 active의 값과 상관없이 btnShadow가 false 일때 잘 실행 되는 것을 확인했다.
사실 이 부분이 이해가 잘 안돼서 좀 더 쉬운 비교대상을 선정하기로 했다. 그것이 바로 배열의 index 값이다.

배열의 index가 생각하기 좀 더 편한 것 같다.
map을 사용하니까 index도 잘 활용해보자

profile
내가 다시 보려고 쓰는 개발.log

0개의 댓글

관련 채용 정보