Toggle 컴포넌트에서 아이콘을 누르면 토글이 보이고 토글 밖을 클릭했을 때 토글이 사라지는 걸 구현하려고 했다.
나는 아이콘을 감싸는 div 태그에 onClick과 onBlur를 넣고
- div 클릭 시 onClick 이벤트로 isOpen을 true or false
- div 밖 클릭 시 onBlur 이벤트로 isOpen을 false
하면 된다고 생각하고 구현했다.
Toggle 컴포넌트 예시
// Toggle 컴포넌트 예시
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Style.ToggleIconWrapper
onClick={() => setIsOpen((prev) => !prev)}
onBlur={() => setIsOpen(false)}
tabIndex="0"
>
<ToggleIcon />
</Style.ToggleIconWrapper>
<Style.ToggleContainer>
{isOpen && (
<Toggle>
<Toggle.Label label="토글 속 라벨" onClick={() => console.log('라벨 클릭!')} />
</Toggle>
)}
</Style.ToggleContainer>
</>
);
하지만 이렇게 되었을때 문제가 하나 생겼다.
라벨을 클릭했을 때 콘솔에 '라벨 클릭!'이라는 문장이 찍히지 않고 토글이 닫히게 된다!!
토글이 닫히는 이유는 토글 버튼 외부를 클릭하면 onBlur 이벤트가 실행되는데 그 외부가 토글도 포함이기 때문에 닫히는 것이다.
그럼 왜 onClick이 실행되지 않고 바로 토글이 닫힌 걸까?
이벤트 핸들러의 작동 순서를 알아야 한다.
onBlur --> onClick
이 순서로 진행되기 때문에 링크를 클릭할 때 onBlur가 먼저 실행이 된 것이다.
그럼 해결방법은?
라벨의 onClick을 onMouseDown로 변경하면 원하던 대로 콘솔에 문장이 찍히고 토글이 닫히게 된다.
onMouseDown은 onBlur보다 더 먼저 실행되기 때문이다.
onMouseDown --> onBlur --> onClick
만약 토글 안의 내용을 클릭했을 때 토글이 안 닫히도록 하려면 onMouseDown에 event.preventDefault()를 넣어주면 된다.
나 같은 경우에는 Toggle 컴포넌트 안에 react-router-dom의 Link가 들어갔기 때문에 onClick이 들어가지 않았다.
그래서 Toggle 컴포넌트를 감싸는 부모 태그에 onMouseDown 이벤트로 preventDefault() 메서드를 호출했다.
...
<Style.ToggleContainer onMouseDown={(event) => event.preventDefault()}>
{isOpen && (
<Toggle>
<Toggle.Label label="토글 속 라벨" onClick={() => console.log('라벨 클릭!')} />
</Toggle>
)}
</Style.ToggleContainer>
https://gist.github.com/juliantrueflynn/d5a2156ca11b01bc8f303ff57bb08681
https://coffeeandcakeandnewjeong.tistory.com/70
https://velog.io/@broccoliindb/onBlur-on-react
'React' 카테고리의 다른 글
[React] 상태 관리 라이브러리의 이해 - Redux 동작 원리 (1) | 2023.02.02 |
---|---|
[React] 상태 관리(feat. React-Query) (0) | 2022.09.03 |
[React] props? state? (0) | 2022.09.01 |
[React] FormData로 image와 json 파일을 저장하여 axios 요청을 보냈지만 안되는 문제 (0) | 2022.07.12 |
ref 오류 : Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()? (0) | 2022.07.06 |