react hooks+ styled components modal창 구현하기

YOUNGJOO-YOON·2021년 4월 20일
0

TOC

  1. 사족

  2. 어떻게 구현할 것인가?

  3. 구현에서의 문제점과 해결책

  4. 구현


0. 사족

react+styled components로 modal을 구현해보려 한다.

이전에 react class component + css를 이용해 구현해본 적이 있기 때문에 그 방식을 그대로 따라가려 했지만 hooks는 다른점이 존재하고 그 방식을 이해하고 구현하기까지 시간이 소비되었다.


1. 어떻게 구현할 것인가?

modal창의 기본은 이미 입력되어 있는 내용의 css display값을 끄고 켜주는게 기본이다.

따라서 component 혹은 DOM 값에 삼항 연산자로 className을 state의 변화에 따라 선택되게 끔 하는 것이 가장 첫 걸음일 것이다.

여기까지는 스무스하게 진행이 된다.

문제는 그 다음이다.

2. 구현에서의 문제점과 해결책

  1. 같은 className의 문제
  2. outside click의 문제

1. 같은 className의 문제

구현에서의 문제점 중 하나는 같은 className을 사용하는 서로 다른 modal 창에 대한 문제점이 있다.

modal_1, modal_2가 있다고 가정하고 이 둘의 className이 같다면 하나의 props.state.isModal 의 값에 대해 동시에 반응하게 된다.

이를 나누어 주는 작업이 필요하다.

2. outside click의 문제

이 문제는 modal창의 기능적인 문제라기 보다는 편의의 문제와 완성도에 연관이 있다.

  1. modal창을 클릭 하여 pop-up이 되었다
  2. 닫기 버튼 혹은 pop-up창 자체를 클릭하면 닫힌다.

여기 까지는 그리 어렵지 않게 구현이 가능하다
하지만 modal창의 바깥쪽을 눌러 modal창을 종료시키려면 다른 방법이 필요하다.

이전에 사용했던 방법은 append에 새로운 element를 생성하고 이를 화면에 꽉 채워준다. 그리고 click 이벤트를 심어두어 modal창의 배경효과와 outside click시 modal 종료라는 두 가지 효과를 한번에 받는 방법을 사용했다.



이번에 사용한 방법은 react.useEffect + react.useRef를 사용했다.
...
export default function ({ isOpen, toggle, children }) {
  const handleClick = (e) => {
);
    if (node.current.contains(e.target)) {
      return;
    }
    if (isOpen) toggle(!isOpen);
  };

  const node = useRef();
  useEffect(() => {
    document.addEventListener("click", handleClick);
    return () => {
      document.removeEventListener("click", handleClick);
    };
  });

  return (
    <Modal ref={node}>
      <div className={isOpen ? "modalOpen" : "modalClose"}>{children}</div>
    </Modal>
  );

위 프로그램의 흐름은
이벤트 발생시 modal창 보여짐 -> useEffect로 document에 대한 click이벤트 감시 -> 이벤트 발생시 modal창 종료
참고 블로그

contains 함수는 Node.contains() 메소드는 주어진 인자가 node 의 자손인지, 아닌지에 대한 Boolean 값을 리턴합니다. -MDN

  const handleClick = () => {
    if (isOpen) toggle(!isOpen);
  };
  useEffect(() => {
    document.addEventListener("click", handleClick);
    return () => {
      document.removeEventListener("click", handleClick);
    };
  }, [isOpen]);
                <Modal isOpen={isModalJsOpen} toggle={setIsModalJsOpen}>
                  <div>ABCDE</div>
                </Modal>

ref가 하는 일이 딱히 없으므로 이런 식으로 변경해도 문제는 없다. 단 toggle시 다른 modal도 useEffect의 state에 함께 반응하기 때문에 (modal의 수 * useEffect의 호출) 이 일어나게 된다. 이를 수정하는 방법은 아직..모르겠다


3. 구현, conclusion

modal창의 구현은 사실 이미 풀려있는 tool을 사용하면 아무 고민없이 modal창을 만들어 낼 수 있지만 만들어 낼 줄 아는 것은 매우 중요하다고 생각한다.

profile
이 블로그의 글은 제 생각을 정리한 글과 인터넷 어딘가에서 배운 것을 정리한 글입니다. 출처는 되도록 남기도록 하겠습니다. 수정 및 건의 오류 등이 있으면 언제든지 댓글 부탁드립니다.

0개의 댓글