useRef 는 당신이 렌더링이 필요 없는 값을 참조 할수 있도록 하는 리액트 훅입니다.
const ref = useRef(initialValue)
ref를 선언하기 위해서 당신의 컴포넌트 최상단에서 useRef를 호출하세요.
import { useRef } from 'react';
function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
// ...
어떠한 타입의 값도 될 수 있습니다. 이 인자는 초기 렌더링 후에 무시되어집니다.
useRef 는 단일 프로퍼티 객체를 반환합니다.
다음 렌더링 과정에서, useRef 는 같은 객체를 리턴합니다.
하나 그 이상의 ref 들을 선언하기 위해서 당신의 컴포넌트 최상단에서 useRef를 호출하세요.
import { useRef } from 'react';
function Stopwatch() {
const intervalRef = useRef(0);
// ...
useRef는 당신이 설정한 초기값을 가지고 있는 current 프로퍼티를 가지고 있는 ref 객체를 반환합니다.
다음 렌더링에서, useRef는 같은 객체를 반환합니다.
당신은 값을 나중에 불러들이거나 저장하기 위해서 current 프로퍼티를 변경할 수 있습니다.
이건 state와 비슷해보이는데, 이 둘 간에는 중요한 차이점이 있습니다.
ref 를 변경하는 것은 리렌더를 유발하지 않습니다.
이건 ref 가 당신의 컴포넌트의 시각적인 부분들에 영향을 끼치지 않고 값들을 완벽히 저장한다는 것을 의미합니다.
예를 들어서, 만약에 당신이 setInterval 값을 저장해두었다가 나중에 사용해야한다면, 그 값을 ref에 넣어둘 수 있습니다.
ref 안에 있는 값을 업데이트 하기 위해서, 당신은 수동적으로 current 프로퍼티 값을 변경 시켜주어야 합니다.
function handleStartClick() {
const intervalId = setInterval(() => {
// ...
}, 1000);
intervalRef.current = intervalId;
}
후에, 당신은 clearInterval 를 호출하기 위해서 ref 로부터 setInterval 값을 읽어올 수 있습니다.
function handleStopClick() {
const intervalId = intervalRef.current;
clearInterval(intervalId);
}
ref 를 사용함으로써, 당신은
ref 는 리렌더를 유발하지 않기때문에, 브라우저 화면상에서 보여지게 하고픈 값을 저장하기에는 부적절합니다.
그러한 조건이라면 state를 사용하는 것이 옳습니다.
useRef 와 useState 둘중에 무엇을 선택해야하는 것인지는 한번 더 읽어보십시오.
이 예시는 state와 ref 둘다 사용합니다. startTime과 now 는 렌더링을 위해서 사용되는 state 변수들입니다.
그러나 우리는 버튼을 눌렀을때 interval 값을 초기화 할수 있도록 하기 위해서 setInterval 값을 갖고 있는 ref 가 필요합니다.
interval ID 는 렌더링에 사용되지 않기때문에, ref 안에서 관리하고 그 안에서 업데이트 하는것이 적절합니다.
ref.current 값을 렌더링하는 동안에 사용하거나 읽지 마십시오.
리액트는 당신의 컴포넌트의 body 가 순수함수처럼 동작하기를 바랍니다.
렌더링 되는 동안에 Ref 값을 변경하거나 사용하는 것은 이러한 부분들을 깨뜨립니다.
function MyComponent() {
// ...
// 🚩 Don't write a ref during rendering
myRef.current = 123;
// ...
// 🚩 Don't read a ref during rendering
return <h1>{myOtherRef.current}</h1>;
}
당신은 대신에 이벤트 핸들러나, useEffect 를 사용함으로써 ref 값들을 수정할 수 있습니다.
function MyComponent() {
// ...
useEffect(() => {
// ✅ You can read or write refs in effects
myRef.current = 123;
});
// ...
function handleClick() {
// ✅ You can read or write refs in event handlers
doSomething(myOtherRef.current);
}
// ...
}
만약 렌더링 되는 동안에 값을 변경해야한다면, useState를 사용하세요.
이러한 규칙을 무시했는데도 컴포넌트는 잘 동작할 수도 있습니다. 하지만 우리가 앞으로 리액트에 추가할 새로운 기능들의 대부분은 이러한 부분들에 의존할 것입니다. 당신의 컴포넌트를 순수한 상태로 유지하세요 를 읽어보세요.
DOM을 조작하기 위해서 ref 를 사용하는 것은 매우 흔한일입니다.
리액트는 이것을 지원합니다. 첫번째로 ref 객체에 초기 값을 저장해서 선언하세요.
import { useRef } from 'react';
function MyComponent() {
const inputRef = useRef(null);
// ...
그 후에 당신이 조작하고 싶은 DOM 노드의 JSX로 ref 속성으로써의 ref 객체를 전달하세요.
// ...
return <input ref={inputRef} />;
리액트가 DOM 노드들을 만들고 그걸 브라우저 화면에 띄운 후에, 리액트는 current 프로퍼티 값을 DOM 노드에 지정합니다.
이제 당신은 input의 DOM 노드에 focus 메서드를 사용함으로써 접근할 수 있습니다.
function handleClick() {
inputRef.current.focus();
}
리액트는 ref 값을 초기렌더링때 저장하고 그 후의 렌더링에서는 무시합니다.
function Video() {
const playerRef = useRef(new VideoPlayer());
// ...
new VideoPlayer 는 초기 렌더링에만 사용되지만, 위의 코드는 매 렌더링마다 이 함수를 호출합니다.
이건 너무 비효율적입니다. 이를 해결하기 위해서 ref 값을 이런식으로 초기화 할 수 있습니다.
function Video() {
const playerRef = useRef(null);
if (playerRef.current === null) {
playerRef.current = new VideoPlayer();
}
// ...
일반적으로, 렌더링동안에 ref.current 값을 수정하거나 읽는것은 용인되지 않습니다. 하지만, 위의 코드처럼 예측 가능하고 초기화될때 항상 같은 값을 리턴하는 경우에는 괜찮습니다.