forwardRef와 useImperativeHandle-Modal

hyeryeon·2024년 8월 18일

React

목록 보기
12/19

기본 개념

1. React Refs

Refs는 React에서 DOM 요소나 컴포넌트 인스턴스에 직접적으로 접근할 수 있게 해 줍니다. 일반적으로, React 데이터 흐름 (props를 통해 부모에서 자식으로 데이터를 전달) 외의 방법을 제공합니다.

2. forwardRef

  • React 컴포넌트가 부모 컴포넌트로부터 ref를 받아 자식 컴포넌트 내부의 DOM 요소나 컴포넌트 인스턴스에 접근할 수 있도록 합니다.
  • 일반적으로 컴포넌트는 자신의 ref를 외부로 노출하지 않으며, ref는 부모와 자식 간에만 내부적으로 사용됩니다. 그러나 forwardRef를 사용하면 부모 컴포넌트가 자식 컴포넌트의 특정 메소드나 변수에 접근할 수 있게 해서, 보다 직접적인 제어나 데이터 교환이 가능해집니다.

3. useImperativeHandle

  • useImperativeHandle은 ref를 사용하여 부모 컴포넌트가 자식 컴포넌트의 인스턴스 값들을 직접 조작할 수 있도록 허용합니다.
    즉, 자식 컴포넌트에서 부모 컴포넌트로 함수나 값들을 "노출"할 때 사용됩니다.
  • 이 훅을 사용하면, 컴포넌트의 내부 구현을 숨기면서도 필요한 기능만을 선택적으로 외부에 제공할 수 있습니다. 이는 캡슐화를 유지하면서도 외부에서 필요한 기능을 사용할 수 있는 방법을 제공합니다.
import { forwardRef, useImperativeHandle, useRef } from 'react';
import { createPortal } from 'react-dom';

const Modal = forwardRef((props, ref) => {
  
  const dialog = useRef();

  useImperativeHandle(ref, () => ({
    open() {
      dialog.current.showModal();
    }
  }));
  return createPortal(
    <dialog ref={dialog}>{props.children}
      <form method="dialog">
        <button>{props.buttonCaption}</button>
      </form>
    </dialog>,
    document.getElementById("modal-root")
  );
});

export default Modal;

forwardRef 사용 :

const Modal = forwardRef((props, ref) => {
  • Modal 컴포넌트를 forwardRef로 감싸서, 이 컴포넌트가 ref를 받을 수 있도록 합니다.
  • forwardRef를 사용하여 부모 컴포넌트로부터 ref를 받을 수 있습니다.

useRef:

  const dialog = useRef();
  • dialog 변수에 useRef()를 사용하여 <dialog> HTML 엘리먼트를 참조합니다.
  • 이 ref는 DOM 요소에 직접 접근할 때 필요합니다.

useImperativeHandle:

  useImperativeHandle(ref, () => ({
    open() {
      dialog.current.showModal();
    }
  }));
  • 부모 컴포넌트가 사용할 수 있도록 open 함수를 ref를 통해 노출합니다.
  • dialog 참조를 사용하여 <dialog> 엘리먼트의 showModal 메서드를 호출합니다.
  • 이 함수는 showModal 메서드를 호출하여 모달을 엽니다.

createPortal:

  return createPortal(
    <dialog ref={dialog}>{props.children}
      <form method="dialog">
        <button>{props.buttonCaption}</button>
      </form>
    </dialog>,
    document.getElementById("modal-root")
  );
});

export default Modal;
  • 모달의 내용을 DOM의 다른 위치(modal-root)에 렌더링하도록 합니다.
  • 모달이 애플리케이션의 다른 부분에서 독립적으로 렌더링되게 합니다.
  • 모달 컨텐츠가 DOM 계층에서 독립적이도록 만들어, 스타일이나 이벤트 처리에서 문제가 생기는 것을 방지합니다.

NewProject 컴포넌트에서 Modal 사용


import { useRef } from 'react';
import Modal from './Modal';

export default function NewProject() {
  const modalRef = useRef();
  //useRef: modalRef를 통해 Modal 컴포넌트의 인스턴스를 참조합니다.

  const handleSave = () => {
    // 입력 검증 로직 후
    if (/* 유효하지 않은 경우 */) {
      modalRef.current.open();
    }
  };

  return (
    <>
      <Modal ref={modalRef} buttonCaption="OK">
        <h2>Invalid Input</h2>
      </Modal>
      <div>
        {/* 폼 입력 필드들 */}
        <button onClick={handleSave}>Save</button>
      </div>
    </>
  );
}

왜 Modal 컴포넌트에 ref를 사용하나요?

모달과 같은 컴포넌트는 보통 사용자의 상호작용(예: 버튼 클릭)에 의해 동적으로 표시되거나 숨겨져야 합니다. React에서 컴포넌트 외부에서 컴포넌트 내부의 메서드(예: 모달 열기)에 접근할 수 있도록 하려면 ref와 forwardRef를 사용하는 것이 효과적입니다.

  • 직접적인 DOM 제어: React에서 직접적인 DOM 조작은 권장되지 않지만, 모달과 같이 복잡한 UI 컨트롤에서는 필수적일 수 있습니다. forwardRef와 useImperativeHandle을 사용하면, React의 선언적 UI 흐름을 벗어나 필요한 경우에만 직접적인 DOM 접근이 가능합니다.

  • 재사용성 및 캡슐화: Modal 컴포넌트는 재사용 가능하며, 그 내부 구현은 외부에 노출되지 않습니다. 다만, 필요한 기능 (open)만을 제공하여 다른 컴포넌트에서 쉽게 사용할 수 있습니다.

0개의 댓글