[21/06/18] 오늘의 개발
모달
다음과 같은 모달을 구현하기 위한 ModalWrapper
컴포넌트를 만들 계획.
- 아이디어 : 모달래퍼는 감싼 컴포넌트, 즉 자식 컴포넌트들을 띄워주는 역할만을 수행한다.
function Modal({ children, setIsModalShow }) {
const modalRef = useRef();
const onClickModal = (e) => {
if (modalRef.current.className === e.target.className) {
// 모달 콘텐츠가아닌 모달 바깥누르는 경우
setIsModalShow(false);
}
};
return (
<Wrapper ref={modalRef} onClick={onClickModal}>
{children}
</Wrapper>
);
}
-
모달 바깥을 누르면 모달은 안보이게된다.
onClickModal
-
children
태그는 모달래퍼로 감싼 자식 컴포넌트
다음은 모달 래퍼의 최상단 컴포넌트이다.
const Wrapper = styled.div`
height: 100%;
position: fixed;
top: 0;
left: 0;
width: 100%;
background-color: rgba(0, 0, 0, 0.5);
`;
position
을 fixed
로 두고, top:0 / left:0를 두어 모달을 구현한다.
useDetectOutsideClick 훅
다음의 코드를 분석해보려고 한다.
const useDetectOutsideClick: any = (el: React.RefObject<HTMLDivElement>, initialState: boolean) => {
const [isActive, setIsActive] = useState(initialState);
useEffect(() => {
const pageClickEvent = (e: Event) => {
if (el.current && !el.current.contains(e.target as Node)) {
setIsActive(!isActive);
}
};
if (isActive) {
window.addEventListener('click', pageClickEvent);
}
return () => {
window.removeEventListener('click', pageClickEvent);
};
}, [isActive, el]);
return [isActive, setIsActive];
};
- 인자 :
el
( div ref object ),initialState
( initial value of isModalShow property )
우선 isModalShow
모달 보여주는 것을 제어할 state
를 만든다.
const [isActive, setIsActive] = useState(initialState);
다음으로 pageClickEvent 리스너 함수를 만들어준다.
const pageClickEvent = (e: Event) => {
if (el.current && !el.current.contains(e.target as Node)) {
// ref 객체의 current, 즉 ref에 값이 잡히는 경우 (렌더 메서드 안에서 ref가 엘리먼트에게 전달되었을 때)
// ref 객체의 current요소가 e.target(클릭한 요소)를 포함하고 있지 않다면, 모달 내부의 컴포넌트가 아닌 외부를 클릭한 경우
// setIsActive(!isActive) isActive를 반대로
setIsActive(!isActive);
}
};
render 메서드 안에서 ref가 엘리먼트에게 전달되었을 때, 그 노드를 향한 참조는 ref의 current 어트리뷰트에 담기게 됩니다.
이렇게 이벤트 리스너를 만들었으면
모달이 켜져있는 경우 이 이벤트 리스너를 달아주고, 모달 컴포넌트가 사라지면 이벤트를 제거한다. (이거 안해주면 이벤트가 누적되어 부착됨)
useEffect(() => {
const pageClickEvent = (e: Event) => {
if (el.current && !el.current.contains(e.target as Node)) {
setIsActive(!isActive);
}
};
if (isActive) {
window.addEventListener('click', pageClickEvent);
}
return () => {
window.removeEventListener('click', pageClickEvent);
};
}, [isActive, el]);
isActive
를 훅을 사용한 컴포넌트에서 받아 모달을 제어하는 데 사용하면 된다.
useEffect vs useLayoutEffect
대부분의 effect는 동기적으로 실행될 필요가 없습니다. 흔하지는 않지만 (레이아웃의 측정과 같은) 동기적 실행이 필요한 경우에는 useEffect와 동일한 API를 사용하는 useLayoutEffect라는 별도의 Hook이 존재합니다.
useEffect
리액트가 effect를 정리(clean-up)하는 시점은 정확히 언제일까요? 리액트는 컴포넌트가 마운트 해제되는 때에 정리(clean-up)를 실행합니다.
Effect를 이용하여 서로 관련이 없는 로직들을 갈라놓을 수 있습니다. 서로 관련 없느 로직은 다른 UseEffect로 분리하도록한다.
의존 배열을 []로 두면, 첫 렌더링 직후 실행
컴포넌트가 처음 나타날때에만 useEffect 에 등록한 함수가 호출됩니다.
Reference
Author And Source
이 문제에 관하여([21/06/18] 오늘의 개발), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@rat8397/210618-오늘의-개발
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Author And Source
이 문제에 관하여([21/06/18] 오늘의 개발), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@rat8397/210618-오늘의-개발저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)