React.js

[React] useRef / forwardRef

문앵 2025. 10. 15. 17:12

일반 ref와 forwardRef의 차이를 알아보자

ref는 보통 포커스나 스크롤이벤트 등 가상 돔을 패스하고 직접 내가 돔노드에 접근하고 싶을 때 쓴다.

 

그럼 forwardRef는 어떤 상황에서 써야 하나?

 

부모 컴포넌트에서 자식 컴포넌트로 ref 를 전달할때 쓴다. ( 이때 ref 는 자식 컴포넌트를 가리키고 있는 상태가 됨 )

그냥 ref 를 전달하면 되는거 아닌가? 라고 생각했지만,

ref는 리액트 내부적으로 만든 특수한 프로퍼티이기 때문에 그냥 컴포넌트간 전달이 막혀있다.

( console.log()에 찍으면 undefined가 뜸 )

 

forwardRef는 컴포넌트간 전달을 할수 있도록 만들어져있다. 그래서 부모 컴포넌트에서 자식 컴포넌트의 돔에 직접 접근할때 사용할 수 있는것이다.

 

사용 방법은 다음과 같다.

 

< useRef >

import {CustomInput} from "../customInput.jsx";

function App(){
	const ref = useRef(null);
    
    return (
		<>
        	<input ref={ref}/> // 이건 가능. ref가 가리키는건 input 돔
            <CustomInput ref={ref}/> // 이건 불가능. 
            // CustomInput 에서 prop 으로 받아와도 undefined가 찍힌다
        </>
    )
}

...

export function CustomInput({ref}){
	console.log(ref); // =undefined
	return <input/>
}

 

 

 

< forwardRef >

import {CustomInput} from "../customInput.jsx";

function App(){
	const ref = useRef(null);
    
    return (
		<>
            <CustomInput ref={ref}/> // 이렇게 사용하고 ref가 가리키는 돔은 CustomInput의 input
        </>
    )
}

...

export const CustomInput =forwardRef((props, ref)=>{
	return <input ref={ref}/>
})

 

 

+ useInperativeHandle

forwardRef와 함께 쓰이는 고급 기능.

이걸 사용하면 자식컴포넌트 내부에서 정의된 함수중 특정 함수만 외부에서 사용할수 있도록 제어할 수 있다.

기존에는 부모 컴포넌트에서 함수를 만들고 이걸 자식 컴포넌트에서 넘겨 받아서 사용하는데,

이렇게 되면 불필요한 리렌더링이 발생할 수 있다.

 

리렌더가 일어나는 이유는 총 세가지인데 챗지피티에 따르면 하위 표와 같다.

props 변경 React의 렌더링 데이터 변경 ✅ 발생
state 변경 React의 렌더링 데이터 변경 ✅ 발생
부모 렌더링 Virtual DOM 재비교 필요 ✅ 발생

 


그런데 useInperativeHandle로 정의된 함수는 

ref.current.method() 호출 -> JS 레퍼런스 호출이기 때문에 React와는 무관하고 따라서 리렌더가 발생하지 않고 함수만 호출하게 되는것.

 

즉, useImperativeHandle의 진짜 의의는?

단순히 부모가 자식 함수 “호출 가능”하게 해주는 게 아니라,
그 호출이 React 렌더 사이클에 영향을 주지 않고 독립적으로 동작하도록 하는 것이다.

그래서 useImperativeHandle을 통해 만든 API는
렌더를 발생시키지 않으면서 컴포넌트의 내부 동작만 수행할 수 있다.
(대표 예: .focus(), .open(), .close())

 

사용법은

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

const CustomInput = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus(),
    clear: () => (inputRef.current.value = "")
  }));

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

function App() {
  const ref = useRef();

  return (
    <>
      <CustomInput ref={ref} />
      <button onClick={() => ref.current.focus()}>포커스</button>
      <button onClick={() => ref.current.clear()}>초기화</button>
    </>
  );
}

 

이런식으로 사용하면 된다

반응형