useRef, useImperativeHandle, createPortal
createPortal
createPortal은 React에서 제공하는 메서드로, 부모 컴포넌트의 DOM 계층 밖에 있는 DOM 노드에 자식 컴포넌트를 렌더링할 수 있게 해줍니다.
용도: 모달, 툴팁, 다른 콘텐츠 위에 나타나야 하는 UI 요소를 렌더링할 때 자주 사용됩니다.
useRef
useRef는 컴포넌트가 리렌더링 되더라도 값이 변하지 않고 유지되는 변수를 관리하는 훅입니다. 값이 변경되어도 컴포넌트 리렌더링을 트리거하지 않습니다.
용도: 주로 DOM 요소에 직접 접근하거나 렌더링 간에 값을 유지해야 할 때 사용됩니다.
useImperativeHandle
useImperativeHandle은 부모 컴포넌트에서 ref를 사용할 때 노출되는 인스턴스 값을 사용자 정의할 수 있는 훅입니다. 이를 통해 부모 컴포넌트가 접근할 수 있는 값과 메서드를 제어할 수 있습니다.
용도: 보통 forwardRef와 함께 사용하여 부모 컴포넌트에 명령형 메서드를 노출하는 컴포넌트를 만들 때 사용됩니다.
사용 예시
createPortal, useRef, useImperativeHandle을 혼합하여 모달 컴포넌트를 만들고 부모 컴포넌트에서 이를 제어할 수 있는 예시입니다:
// 모달 컴포넌트
const Modal = forwardRef((props, ref) => {
const [isOpen, setIsOpen] = useState(false);
// 부모 컴포넌트에 open과 close 메서드를 노출
useImperativeHandle(ref, () => ({
open: () => setIsOpen(true),
close: () => setIsOpen(false),
}));
// 모달 콘텐츠를 포탈로 렌더링
if (!isOpen) return null;
return createPortal(
<div className="modal">
<div className="modal-content">
{props.children}
<button onClick={() => setIsOpen(false)}>닫기</button>
</div>
</div>,
document.body // 또는 특정 DOM 노드
);
});
// 부모 컴포넌트
const App = () => {
const modalRef = useRef();
const openModal = () => {
if (modalRef.current) {
modalRef.current.open();
}
};
return (
<div>
<h1>React Portals와 Imperative Handle 예시</h1>
<button onClick={openModal}>모달 열기</button>
<Modal ref={modalRef}>
<h2>모달 콘텐츠</h2>
<p>React Portals, useRef, useImperativeHandle을 사용하는 예시입니다.</p>
</Modal>
</div>
);
};
설명
Modal 컴포넌트:
forwardRef를 사용하여 부모 컴포넌트로부터 전달받은 ref를 전달합니다.
useImperativeHandle을 사용하여 부모 컴포넌트에 open과 close 메서드를 노출합니다.
createPortal을 사용하여 자식 콘텐츠를 부모 컴포넌트의 DOM 계층 밖에 렌더링합니다.
App 컴포넌트:
모달 컴포넌트를 참조하기 위해 useRef를 정의합니다.
"모달 열기" 버튼이 클릭되면 ref를 통해 모달 컴포넌트의 open 메서드를 호출합니다.
결론
이 예시는 createPortal을 사용하여 부모 컴포넌트의 DOM 계층 밖에 모달을 렌더링하고, useRef를 사용하여 모달 컴포넌트를 참조하며, useImperativeHandle을 사용하여 부모 컴포넌트가 모달의 열림/닫힘 상태를 제어할 수 있게 하는 방법을 보여줍니다.