// 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도 잘 활용해보자