clickOutside close 구현하기

이경준·2021년 3월 19일
0


기본토글버튼에서 바깥을 클릭했을때 close되면서 해당 target을 클릭했을때는 open을 유지하는 기능을 재사용가능한 hook으로 구현해보았다.

1. jsx 태그 구조

// 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일경우 사라지게 구현하였다.

2. 커스텀 hook만들기

먼저 외부 파일에 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;
  1. useRef를 사용하여 버튼과 옵션태그를 지정할 것이다.
  2. 버튼태그가 클릭한 태그를 contains하고 있을경우 토글이되게하고
  3. 옵션태그가 포함되지않을경우 false로 바꿔 사라지게 한다.
  4. return 함수를 사용하여 클릭이벤트를 삭제한다.

3. hook 사용하기

//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이 완성된다.

profile
내가 기억하기위한 블로그

0개의 댓글