const ref = useRef(initialValue)
useRef는 저장공간 또는 DOM요소에 접근하기 위해 사용되는 React Hook이다. 여기서 Ref는 reference, 즉 참조를 뜻한다. 자바스크립트에서 특정 DOM 을 선택하기 위해서 querySelector 등의 함수를 사용했다. React에서도 DOM을 직접 선택해야 하는 상황이 존재한다. 그 때 useRef가 아닌 querySelector 등을 사용하면 안 될까?
React는 렌더링을 하며 virtual DOM을 먼저 만들고, virtual DOM과 실제 DOM을 비교하여 차이가 있는 부분만 리렌더링 하는 방식을 통해 효율적으로 처리한다. 이때 React에 useRef가 없다고 가정하고, getElementById를 통해 특정 DOM을 선택한다면, 재사용성에 문제가 발생한다. id는 HTML 요소마다 고유해야 하기 때문에, 여러 컴포넌트를 재사용하면서 같은 id를 부여하면 문제가 생길 수 있다. React에서 컴포넌트를 여러 번 사용한다고 가정할 때, 각 컴포넌트 안에 동일한 id를 가진 DOM 요소가 생긴다. 이는 브라우저가 id를 고유하게 관리하기 때문에 충돌을 일으킬 수 있다. 이러한 문제 때문에 useRef를 사용하여 DOM 요소에 접근하면, 컴포넌트를 재사용할 때마다 DOM 요소의 참조가 변경되지 않아 문제가 발생하지 않는다.
useState와의 차이는 아래와 같다.
useState
컴포넌트의 상태를 관리할 때 사용한다. 상태가 변할 때마다 컴포넌트를 다시 렌더링하고 싶을 때 주로 사용된다. 상태를 변경하면 해당 컴포넌트가 다시 렌더링된다.
useRef
이전 값과 새로운 값을 연결하고, 렌더링과는 무관하게 값이 유지되어야 할 때 사용한다. 주로 DOM 요소나 외부 라이브러리의 인스턴스와 같이 렌더링과는 직접적으로 관련이 없는 값들을 저장할 때 사용된다.
ref는 HTML 엘리먼트 접근이라는 특수한 용도로 사용되기 때문에 일반적인 prop으로 사용을 할 수 없다. HTML 엘리먼트가 아닌 React 컴포넌트에서 ref prop을 사용하려면 forwardRef 함수를 사용해야 한다. React 컴포넌트를 forwardRef로 감싸주면, 해당 컴포넌트는 함수는 두 번째 매개 변수를 갖게 되어 외부에서 ref prop을 넘길 수 있다.
function CustomInput() {
return <input />;
}
function ParentComponent() {
const customInputRef = useRef(null);
return <CustomInput ref={customInputRef} />; // 오류 발생
}
const CustomInput = React.forwardRef((props, ref) => {
return <input ref={ref} {...props} />; // 전달받은 ref를 실제 DOM 요소에 연결
});
function ParentComponent() {
const customInputRef = useRef(null);
const handleFocus = () => {
customInputRef.current.focus(); // CustomInput에 접근 가능!
};
return <CustomInput ref={customInputRef} />;
}
React에서 함수형 컴포넌트에서 ref를 사용할 때, 부모 컴포넌트가 자식 컴포넌트의 인스턴스를 제어할 수 있도록 특정 값을 노출하는 데 사용되는 훅이다. 이 훅은 forwardRef와 함께 사용되어, 자식 컴포넌트가 부모로부터 ref를 받을 수 있게 한다.
useImperativeHandle 훅을 사용하여 부모가 사용할 수 있는 API를 정의할 수 있다. 이 API는 함수나 객체로 구성되어 부모가 자식 컴포넌트의 특정 기능에 접근할 수 있게 한다.
import React, { useImperativeHandle, useRef, forwardRef } from 'react';
// 자식 컴포넌트
const CustomInput = forwardRef((props, ref) => {
const inputRef = useRef();
// 부모가 사용할 수 있는 함수 정의
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus(); // input에 포커스
},
clear: () => {
inputRef.current.value = ''; // input 값을 지우기
}
}));
return <input ref={inputRef} {...props} />;
});
// 부모 컴포넌트
const ParentComponent = () => {
const inputRef = useRef();
const handleFocus = () => {
if (inputRef.current) {
inputRef.current.focus(); // 자식 컴포넌트의 focus 함수 호출
}
};
const handleClear = () => {
if (inputRef.current) {
inputRef.current.clear(); // 자식 컴포넌트의 clear 함수 호출
}
};
return (
<div>
<CustomInput ref={inputRef} />
<button onClick={handleFocus}>Focus Input</button>
<button onClick={handleClear}>Clear Input</button>
</div>
);
};
export default ParentComponent;
HOC(Higher-Order Component)은 컴포넌트를 인자로 받아 새로운 컴포넌트를 반환하는 함수이다. HOC는 코드 재사용을 위해 자주 사용된다. forwardRef는 부모 컴포넌트에서 자식 컴포넌트로 ref를 전달할 수 있도록 해주는 HOC이다. 이때 자식 컴포넌트가 익명 함수로 정의되면, 컴포넌트 이름이 Anonymous 또는 자동 생성된 이름으로 표시되어 디버깅이 어렵다. 이럴 경우 displayName을 설정하면, 개발자 도구에서 더 나은 식별이 가능하다.
CustomInput.displayName = "CustomInput";
React에서 DOM 엘리먼트나 컴포넌트 인스턴스에 대한 참조를 관리하는 방법 중 하나로, 함수를 사용하여 참조를 설정하고 업데이트하는 방식. React가 해당 DOM 엘리먼트를 마운트하거나 언마운트할 때 호출된다. callback ref를 사용하면 특정 상황에서 더 유연하게 DOM 노드에 접근할 수 있다. 예를 들어, 특정 상태에 따라 ref를 다르게 설정해야 하는 경우에 유용하다.
useRef를 사용한 경우에는 다음과 같이 사용하게 된다.
import React, { useRef } from 'react';
const UseRefExample = () => {
const inputRef = useRef(null);
const focusInput = () => {
if (inputRef.current) {
inputRef.current.focus(); // DOM 노드에 직접 접근
}
};
return (
<div>
<input type="text" ref={inputRef} placeholder="Focus me" />
<button onClick={focusInput}>Focus Input</button>
</div>
);
};
export default UseRefExample;
반면, callback Ref는 다음과 같이 사용한다.
import React, { useRef } from 'react';
const CallbackRefExample = () => {
const inputRef = useRef(null);
const setInputRef = (element) => {
inputRef.current = element; // DOM 노드를 참조
if (element) {
element.focus(); // 마운트 시 포커스
}
};
return (
<div>
<input type="text" ref={setInputRef} placeholder="Focus me on mount" />
<button onClick={() => inputRef.current && inputRef.current.focus()}>
Focus Input
</button>
</div>
);
};
export default CallbackRefExample;
[React] useRef란?
[React] useRef에 대한 이해와 특정 DOM 조작 (부제: useRef로 특정 DOM 선택)