[React] 학습 - day2

jiseong·2021년 9월 17일
0

T I Learned

목록 보기
74/291

특정 영역 외 클릭 시 팝업 닫기

현재 검색폼의 구조는 다음과 같다.
각 특정 영역을 누를 때마다 해당 영역에 해당하는 팝업창이 보이게 된다.

하지만 그 외 영역을 누를때는 팝업이 닫히게 하고 싶었다.

<div css={searchForm}>
  <div name="location" css={searchFormCol} onClick={changePopupType}>
    <h5>위치</h5>
    <input type="text" className="query-input" placeholder="어디로 여행가세요?" />
  </div>
  <LocationPopup popupState={popupType === 'location'} />
  <div css={serachFormDivide}></div>
  <div name="calendar" css={searchFormCol} onClick={changePopupType}>
    <h5>체크인</h5>
    <p>날짜 입력</p>
  </div>
  <div css={serachFormDivide}></div>
  <div name="calendar" css={searchFormCol} onClick={changePopupType}>
    <h5>체크아웃</h5>
    <p>날짜 입력</p>
  </div>
  <CalendarPopup popupState={popupType === 'calendar'} />
  <div css={serachFormDivide}></div>
  <div name="guest" css={[searchFormCol, searchFormColLast]} onClick={changePopupType}>
    <div>
      <h5>인원</h5>
      <p>게스트 추가</p>
    </div>
    <button>
      <SearchIcon />
    </button>
  </div>
  <GuestPopup popupState={popupType === 'guest'} />
</div>

parentNode

첫 번째 방법으로,
e.target 와 parentNode를 이용하여 실제 누른 영역에 부모 영역 또는 부모의 부모 영역을 찾아 검색폼 영역 내부에 해당하는지 찾아 가려고 했다.

하지만, 비효율적인 것 같아서 포기..

function resetType(e) {
    console.log(e.target.parentNode);
  }

useEffect(() => {
  window.addEventListener('click', resetType);
  return () => {
    window.removeEventListener('click', resetType);
  };
}, []);

useRef

두 번째 방법으로,
getElementById, querySelector 같은 DOM Selector 함수를 사용해서 DOM 을 선택하는 방식과 동일한 useRef를 이용하였다.

검색 폼 DOM을 가져와 현재 클릭한 e.target이 포함되어있는지 아닌지 contains 함수를 이용해 판별하여 popup을 조작할 수 있었다.

const refSearchForm = useRef();

function resetType(e) {
  if (!refSearchForm.current?.contains(e.target)) setPopupType(undefined);
}

useEffect(() => {
  window.addEventListener('click', resetType);
  return () => {
    window.removeEventListener('click', resetType);
  };
}, []);

return (
    <div css={searchForm} ref={refSearchForm}>
		/* 생략 */
    </div>
);

🔖 demo

+ 체크인, 체크아웃에 해당하는 달력기능만 구현해볼 생각인데 고려할게 너무 많다.. 일단 작게 따로 달력을 만들어보고 적용해볼 생각이다.

0개의 댓글