ref, forwardRef는 제가 리액트를 공부하면서 생소하게 느낀 부분 중 하나였습니다. 특히 타입스크립트랑 같이 사용하는 경우에는 이 녀석의 타입이 MutableRefObject
와RefObject
로 나뉘더라구요?
그래서 ref, forwardRef를 확실히 알고 넘어가려합니다.
ref는 DOM node를 부모 컴포넌트에 노출시켜, 부모 컴포넌트가 해당 DOM node를 직접 조작할 수 있도록 하는 리액트만의 기술입니다. 함수형 컴포넌트에서 사용을 할 때는 useRef()
훅을 사용하는데요, useRef는 current 프로퍼티가 들어있는 객체를 리턴합니다.
그런데 리턴타입이 두 종류입니다. MutableRefObject
, 그리고 RefObject
이렇게요.
MutableRefObject와 RefObject는 같은 생김새지만, current
프로퍼티가 readonly라는 점이 다릅니다.
interface MutableRefObject<T> {
current: T;
}
interface RefObject<T> {
readonly current: T | null;
}
리액트 공식문서의 예시에서는 useRef
를 null로 초기화하며 선언해주고, 리턴받은 ref를 Element의 ref 프로퍼티에 넘겨줍니다.
React will assign the current property with the DOM element when the component mounts, and assign it back to null when it unmounts. ref updates happen before componentDidMount or componentDidUpdate lifecycle methods.
예전 리액트 공식문서에 따르면 리액트는 컴포넌트가 마운트될 때, ref의 current프로퍼티에 DOM요소를 할당하고, 언마운트될 때 null을 할당합니다. ref에 대한 업데이트는 컴포넌트가 마운트되기 전(componentDidMount
), 그리고 컴포넌트가 업데이트(componentDidUpdate
)전 라이프사이클에서 진행이 됩니다.
이 말인 즉슨, 컴포넌트가 마운트가 완료되었거나 업데이트가 완료된 시점에는 ref.current
가 초기화/또는 업데이트가 완료되어있기에 우리는 안심하고 ref.current
에 접근해 값을/요소를 조작할 수 있다는 의미입니다.
import { useRef } from 'react';
export default function Form() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} />
<button onClick={handleClick}>
Focus the input
</button>
</>
);
}
그런데 이 차이가 있나요? 리액트 깃허브의 코드를 보면 별 차이가 없는 것 같아요.
last update: 2023.08.10
This happens because by default React does not let a component access the DOM nodes of other components. Not even for its own children! This is intentional. Refs are an escape hatch that should be used sparingly. Manually manipulating another component’s DOM nodes makes your code even more fragile.
리액트는 다른 컴포넌트의 DOM 노드에 직접적으로 접근하여 조작하는 것을 지양하는 듯 합니다. 리액트는 가상 DOM트리를 나중에 HTML과 합치기에, 직접적으로 브라우저 DOM노드에 접근하여 무분별하게 조작하는 것은 위험한 시도라는 생각이 듭니다. 그래서 sparingly(절약하여) Ref를 사용하라고 하는 것일 수 있겠네요.
(아직 학습중입니다)
https://react.dev/learn/manipulating-the-dom-with-refs#how-to-manage-a-list-of-refs-using-a-ref-callback
(아직 학습중입니다)
https://react.dev/reference/react/useImperativeHandle