보통 ref
는 DOM 요소에 직접 접근할 때 사용하지만,
useImperativeHandle
과 forwardRef
를 조합하면 컴포넌트 외부에서 내부 메서드에 접근할 수 있어.
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타입>
형식으로 지정.
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}>로 연결하면 외부 제어가 가능해져.
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, () => ({ ... }))로 외부에서 접근 가능한 메서드 인터페이스를 정의할 수 있어.
const Parent = () => {
const customRef = useRef<InputHandle>(null);
return (
<>
<CustomInput ref={customRef} />
<button onClick={() => customRef.current?.focus()}>포커스</button>
</>
);
};
✅ 자식 컴포넌트에서 내부 DOM에만 ref를 연결하고, 외부에는 커스텀 메서드만 노출하는 구조. 캡슐화에 좋고 재사용성도 높아져.