기본토글버튼에서 바깥을 클릭했을때 close되면서 해당 target을 클릭했을때는 open을 유지하는 기능을 재사용가능한 hook으로 구현해보았다.
// app.js
return (
<Styled.TotalContainer>
<Styled.OptionBox>
<Styled.OptionContainer> //클릭버튼
<p>Options</p>
<i class='fas fa-chevron-down'></i>
</Styled.OptionContainer>
<Styled.OptionListContainer> //옵션
<Styled.OptionList>
<i class='far fa-edit'></i>
<span>Edit</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='fas fa-clone'></i>
<span>Duplicate</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='fas fa-archive'></i>
<span>Archive</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='fas fa-arrow-alt-circle-right'></i>
<span>Move</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='far fa-handshake'></i>
<span>Share</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='fas fa-heart'></i>
<span>Add to favorite</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='fas fa-trash-alt'></i>
<span>Delete</span>
</Styled.OptionList>
</Styled.OptionListContainer>
</Styled.OptionBox>
</Styled.TotalContainer>
);
아이콘은 font-awesome에서 사용하였으며, css는 다른파일의 styled-components로 구성하였다.
'클릭버튼'을 클릭하였을때 true일 경우 '옵션'이 나타나고 false일경우 사라지게 구현하였다.
먼저 외부 파일에 useClickOutside.js파일을 만든다.
// useClickOutside.js
import { useRef, useEffect, useState } from "react";
const useClickOutside = (initialValue) => {
const buttonRef = useRef();
const visibleContentRef = useRef();
const [visible, setVisible] = useState(initialValue);
useEffect(() => {
const buttonHandeler = (event) => {
if (buttonRef.current.contains(event.target)) {
setVisible((prev) => !prev);
} else if (!visibleContentRef.current.contains(event.target)) {
setVisible(false);
}
};
document.addEventListener("click", buttonHandeler);
return () => {
document.addEventListener("click", buttonHandeler);
};
}, []);
return [buttonRef, visibleContentRef, visible];
};
export default useClickOutside;
//app.js
import useClickOutside from "./useClickOutside";
const App = () => {
const [buttonRef, visibleContentRef, visible] = useClickOutside(false);
return (
<>
<Styled.GlobalStyle />
<Styled.TotalContainer>
<Styled.OptionBox>
<Styled.OptionContainer ref={buttonRef}>
<p>Options</p>
<i class='fas fa-chevron-down'></i>
</Styled.OptionContainer>
<Styled.OptionListContainer toggle={visible} ref={visibleContentRef}>
<Styled.OptionList>
<i class='far fa-edit'></i>
<span>Edit</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='fas fa-clone'></i>
<span>Duplicate</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='fas fa-archive'></i>
<span>Archive</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='fas fa-arrow-alt-circle-right'></i>
<span>Move</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='far fa-handshake'></i>
<span>Share</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='fas fa-heart'></i>
<span>Add to favorite</span>
</Styled.OptionList>
<Styled.OptionList>
<i class='fas fa-trash-alt'></i>
<span>Delete</span>
</Styled.OptionList>
</Styled.OptionListContainer>
</Styled.OptionBox>
</Styled.TotalContainer>
</>
);
};
클릭하게될 버튼과 나타나게될 옵션만 ref로 지정해주면 재사용가능한 hook이 완성된다.