TIL30, React: outside click 구현하기

sunghoonKim·2020년 12월 29일
5

아웃사이드 클릭을 구현해봅시다.


아이디어

는 매우 간단하다. Node1.contains(node2) 를 이용한다. 더 자세한 내용은 공식문서를 참조. 간단히 설명하자면, Node1node2 를 포함하는지에 대한 boolean 값을 리턴하는 메소드이다. 이것을 이용, 다음과 같이 outside click 을 구현할 수 있다.

  1. 문서 전체에 이벤트 리스너를 붙여준다. 클릭이므로 이벤트 종류는 mousedown 이다.
  2. 아웃 사이드 클릭의 기준이 될 HTML 요소를 잡아준다. React ref 를 이용.
  3. 이벤트가 발생했을 때, event의 target이 ref에 저장된 요소를 포함하는지 확인한다.
  4. 포함이 되지 않는다면 바깥쪽 클릭이 된 것. 이를 조건으로 내가 원하는 액션을 취한다.

코드로 풀어봅시다.


코드

class Navigation extends Component {
  state = { isHamburgerClicked: false };
  hamburgerRef = React.createRef(); // 1. ref 를 만들어주고

  componentDidMount() {
    document.addEventListener("mousedown", this.handleClickOutside); // 0. 이벤트 리스너를 할당.
  }

  componentWillUnmount() {
    document.removeEventListener("mousedown", this.handleClickOutside);
  }

  handleClickOutside = event => {
    console.log("event target is: ", event.target);
    if (!this.hamburgerRef.current.contains(event.target)) { // 3. outside click 인지 판단
      this.setState({
        isHamburgerClicked: false,
      });
    }
  };

  handleClick = () => {
    this.setState({ isHamburgerClicked: !this.state.isHamburgerClicked });
  };

  render() {
    const { isHamburgerClicked } = this.state;
    return (
      <nav className="Navigation">
        <section>
          <img src="/images/Navigation/airbnb.png" alt="codebnb" />
          <span>codebnb</span>
        </section>
        <section></section>
        <section>
          <div className="host">호스트 되기</div>
          <div onClick={this.handleClick} className="hamburgerMenu" ref={this.hamburgerRef}> // 2. 여기에 ref를 붙인다
            <HamburgerIcon />
            <img src="/images/Navigation/user_default.png" alt="user" />
            <div className={`popup ${isHamburgerClicked ? "" : "hide"}`}>
              <div>로그인</div>
              <div>회원가입</div>
              <div>숙소 호스트 되기</div>
              <div>체험 호스트 되기</div>
              <div>도움말</div>
            </div>
          </div>
        </section>
      </nav>
    );
  }
}

데모


ㅗㅜㅗㅜ 👊

3개의 댓글

comment-user-thumbnail
2020년 12월 29일

좋은 글 잘 읽었습니다 :)

답글 달기
comment-user-thumbnail
2021년 7월 23일

감사합니다

답글 달기
comment-user-thumbnail
2023년 7월 5일

군더더기 없는 아주 좋은 예제입니다. 감사합니다

답글 달기