reactrefforwardref
React ref와 forwardRef - DOM 접근과 컴포넌트 간 ref 전달
✨ AI 요약
긴 글, 핵심만 먼저 — 이 글을 3줄로 정리해드려요.
조회 0
React에서 DOM 요소에 직접 접근하거나, 자식 컴포넌트의 메서드를 호출할 때 ref를 사용합니다.
이 글에서는 useRef, forwardRef, useImperativeHandle의 사용법과 실무 패턴을 정리합니다.
1. useRef 기본 사용법
function TextInput() {
const inputRef = useRef<HTMLInputElement>(null);
const focusInput = () => {
inputRef.current?.focus();
};
return (
<>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>포커스</button>
</>
);
}
ref.current는 DOM 요소나 컴포넌트 인스턴스를 가리킵니다.null로 초기화하고, 마운트 후에 값이 할당됩니다.
2. forwardRef로 ref 전달
함수 컴포넌트는 기본적으로 ref를 받을 수 없으므로, forwardRef로 래핑해야 합니다.
const CustomInput = forwardRef<HTMLInputElement, { label: string }>(
({ label }, ref) => {
return (
<label>
{label}
<input ref={ref} type="text" />
</label>
);
}
);
forwardRef는 두 번째 인자로ref를 받습니다.
3. useImperativeHandle로 커스텀 ref API
자식 컴포넌트가 부모에게 노출할 메서드를 제한할 수 있습니다.
const CustomInput = forwardRef<{ focus: () => void }, { label: string }>(
({ label }, ref) => {
const inputRef = useRef<HTMLInputElement>(null);
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current?.focus();
},
}));
return <input ref={inputRef} type="text" />;
}
);
- 부모는
ref.current.focus()만 호출할 수 있고, 내부inputRef는 접근할 수 없습니다.
4. ref를 통한 값 저장
ref는 DOM 접근뿐 아니라, 렌더링과 무관한 값을 저장하는 데도 사용됩니다.
function Timer() {
const intervalRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
intervalRef.current = setInterval(() => {
console.log("tick");
}, 1000);
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, []);
// intervalRef.current를 읽어도 리렌더링이 발생하지 않음
}
ref.current를 변경해도 리렌더링이 발생하지 않습니다.
5. 실무 팁
- DOM 접근이 꼭 필요한가?: 대부분의 경우 state/props로 해결 가능하므로, ref 사용을 최소화
- 타입 안정성:
useRef<HTMLInputElement>(null)처럼 타입을 명시 - null 체크:
ref.current?.로 옵셔널 체이닝 사용
ref는 "명령형" 접근이 필요한 경우에만 사용하는 것이 좋습니다.
대부분의 경우 React의 선언적 패러다임으로 해결할 수 있으므로, ref 사용 전에 "정말 필요한가?"를 한 번 더 생각해보세요.