import React, { useState } from "react";
import Arrow from "../icon/dropdown-arrow";
type DropdownItem = {
name: string;
id: string;
};
type DropdownProps = {
items: DropdownItem[];
};
function DropDown({ items }: DropdownProps) {
const [isDropdownOpen, setIsDropdownOpen] = useState<boolean>(false);
const [selectedItem, setSelectedItem] = useState<string>("선택");
return (
<div
className="bg-[#f5f5f5] rounded-[5px]"
onBlur={() => {
setIsDropdownOpen(false);
}}
>
<button
onClick={() => {
setIsDropdownOpen((prev) => !prev);
}}
className="w-[240px] bg-[#F5F5F5] h-[50px] rounded-[5px] flex items-center justify-between p-[16px]"
>
<div className={`${selectedItem === "선택" && "text-[#a0a0a0]"} w-fit`}>{selectedItem}</div>
<div className={`${isDropdownOpen && "rotate-180"}`}>
<Arrow />
</div>
</button>
<div
className={`${
isDropdownOpen ? "" : "hidden"
} absolute bg-[#f5f5f5] w-[240px] rounded-bl-[5px] rounded-br-[5px] `}
>
{items.map((item) => (
<div
key={item.id}
className="h-[50px] text-left p-[16px] cursor-pointer"
onClick={() => {
setSelectedItem(item.name);
setIsDropdownOpen(false);
}}
>
{item.name}
</div>
))}
</div>
</div>
);
}
export default DropDown;
만들어본 드롭다운 컴포넌트의 코드는 다음과 같다.
기본 버튼을 클릭하면 메뉴가 펼쳐지고 메뉴 중에 하나를 클릭하면 state에 저장한 후 드롭다운이 닫히는 구조이다.
여기서 드롭다운이 펼쳐져 있을 때 밖의 화면을 클릭하면 자동으로 닫힐 수 있도록 설정하려고 했는데...
아래와 같은 상황이 펼쳐졌다.

상황파악을 해보자면 드롭다운 메뉴의 onClick에 대한 함수가 적용되는 것이 아니라 onBlur에 대한 함수가 적용되어 선택값이 state에 반영되지 않고 드롭다운만 계속 닫히게 된다.
어떻게 된 일이지...?
구글링을 해보니 답을 찾았다...!

어떤 태그(컴포넌트)에 대해서 이벤트에 대한 우선순위가 있었다.
위쪽일수록 우선순위가 높은 이벤트이다.
나는 onBlur와 onClick 간의 우선순위 비교가 필요했는데 blur > focus > mouseup> click 이기 때문에 blur 이벤트가 우선시 되어 실행되게 된다. onBlur의 우선순위가 더 높기 때문에 onClick 대신 onBlur의 함수가 대신 실행된 것이다.
클릭과 거의 흡사한 역할을 하지만 우선순위가 더 높은 mousedown으로 코드를 바꿔보았다.
<div
key={item.id}
className="h-[50px] text-left p-[16px] cursor-pointer"
onMouseDown={() => {
setSelectedItem(item.name);
setIsDropdownOpen(false);
}}
>
{item.name}
</div>

성공적으로 원하는 동작을 만들었다.
메뉴가 클릭될 때마다 state에 반영도 잘 되고 있고 blur 이벤트일 때 state값을 유지한 채로 메뉴가 잘 닫히는 것도 확인할 수 있었다.
오늘 배운 것
이벤트에도 우선순위가 있다. 이벤트 종류만 무작정 외워서 쓸 생각 하지 말고 우선순위가 있다는 걸 명심하고 적절하게 사용하자.
참고:
'웹 > React' 카테고리의 다른 글
React - 가로 스크롤바 간단하게 만들기 (feat. tailwindCSS) (0) | 2023.12.04 |
---|---|
React 드롭다운 메뉴 혼자서 만들어보기 - 라이브러리 X (0) | 2023.08.07 |
React Axios Post FormData - 이미지랑 JSON 같이 보내기 (에러 엄청 난 후기) (0) | 2022.11.23 |