보통 ref는 DOM 요소에 직접 접근할 때 사용하지만,

useImperativeHandleforwardRef를 조합하면 컴포넌트 외부에서 내부 메서드에 접근할 수 있어.


📘 예제 56: ref 전달형 컴포넌트

import { forwardRef } from 'react';

type InputProps = {
  label: string;
};

const TextInput = forwardRef<HTMLInputElement, InputProps>(({ label }, ref) => {
  return (
    <label>
      {label}
      <input ref={ref} />
    </label>
  );
});

✅ forwardRef는 ref를 props처럼 컴포넌트에 전달할 수 있게 해주는 고차 컴포넌트야.

타입은 forwardRef<ref타입, props타입> 형식으로 지정.


📘 예제 57: forwardRef 기본 사용법

import { useRef } from 'react';

const Parent = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  return (
    <>
      <TextInput label="이름" ref={inputRef} />
      <button onClick={() => inputRef.current?.focus()}>포커스</button>
    </>
  );
};

✅ 부모 컴포넌트에서 ref를 직접 넘기고, 자식 컴포넌트에서 <input ref={ref}>로 연결하면 외부 제어가 가능해져.


📘 예제 58: useImperativeHandle로 내부 메서드 노출

import { useImperativeHandle, useRef, forwardRef } from 'react';

type InputHandle = {
  focus: () => void;
};

const CustomInput = forwardRef<InputHandle>((props, ref) => {
  const inputRef = useRef<HTMLInputElement>(null);

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current?.focus();
    },
  }));

  return <input ref={inputRef} />;
});

✅ useImperativeHandle(ref, () => ({ ... }))로 외부에서 접근 가능한 메서드 인터페이스를 정의할 수 있어.


📘 예제 59: 컴포넌트 재사용 예제

const Parent = () => {
  const customRef = useRef<InputHandle>(null);

  return (
    <>
      <CustomInput ref={customRef} />
      <button onClick={() => customRef.current?.focus()}>포커스</button>
    </>
  );
};

✅ 자식 컴포넌트에서 내부 DOM에만 ref를 연결하고, 외부에는 커스텀 메서드만 노출하는 구조. 캡슐화에 좋고 재사용성도 높아져.