개념
useRef는 리렌더링 하지 않는다. 컴포넌트의 속성만 조회&수정한다.
→ 개인적인 견해로 여러 글을 보았는데 위의 문장이 제일 useRef()를 잘 설명해주는 것 같다.
사용
useRef함수는 current속성을 가지고 있는 객체를 반환한다. 인자로 넘어온 초기값을 current속성에 할당한다. 이 current속성은 값을 변경해도 상태를 변경할 때 처럼 React 컴포넌트가 다시 랜더링되지 않는다. 위에서 정의한 것처럼 리랜더링되지 않기 때문이다. React 컴포넌트가 다시 랜더링될 때도 마찬가지로 이 current 속성의 값이 유실되지 않는다.
import React, { useState, useRef } from "react";
function ManualCounter() {
const [count, setCount] = useState(0);
const intervalId = useRef(null);
console.log(`랜더링... count: ${count}`);
const startCounter = () => {
intervalId.current = setInterval(
() => setCount((count) => count + 1),
1000
);
console.log(`시작... intervalId: ${intervalId.current}`);
};
const stopCounter = () => {
clearInterval(intervalId.current);
console.log(`정지... intervalId: ${intervalId.current}`);
};
return (
<>
<p>자동 카운트: {count}</p>
<button onClick={startCounter}>시작</button>
<button onClick={stopCounter}>정지</button>
</>
);
}
위 코드를 보면 count가 1000이 될 때까지 1씩 올려준다. 정지버튼으로 초기화시킬 수 있다.
용도
1) 저장공간 관리
react 컴포넌트는 state가 변할 떄마다 다시 랜더링이 되면서 컴포넌트 내부의 변수들이 초기화가 된다. 그리고 모든 함수 로직이 다시 실행된다.
useRef()는 랜더링이되지 않기에 이를 사용하여 불필요한 랜더링을 안 해도 된다. 그리고 랜더링이 아무리 되어 ref안에 있는 값은 변화되지 않는다. 그래서 랜더링되지 않아야 되는 값을 관리해야 했을 때 선언할 때 좋다.
2) DOM요소에 접근
- 변수 관리 : 이는 자바스크립트 document.querySelector()와 비슷하다.
import { useState, useRef } from 'react'
import './App.css';
function App() {
const [render, setRender] = useState(false);
const countRef = useRef(0);
let countVar = 0;
console.log('***** 렌더링 후 Ref:', countRef.current);
console.log('***** 렌더링 후 Var:', countVar);
const increaseRef = () => {
countRef.current = countRef.current + 1;
console.log('Ref Up! --->', countRef.current);
}
const increaseVar = () => {
countVar = countVar + 1;
console.log('Var Up! --->', countVar);
}
const doRender = () => {
setRender(!render);
}
return (
<div className="App">
<header className="App-header">
<p>Ref: {countRef.current}</p>
<p>Var: {countVar}</p>
<div>
<button onClick={increaseRef}>Ref Up!</button>
<button onClick={increaseVar}>Var Up!</button>
<button onClick={doRender}>Render!</button>
</div>
</header>
</div>
);
}
export default App;
버튼을 클릭시 값이 변하게 된다. 랜더를 눌렀을 때 useRef에 할당한 값이 잘 나오게 된다. 랜더링이 될 떄마다 컴포넌트 함수 내부에 있는 변수들이 다시 초기화 되어 var의 값은 0이 된다. 그러나 ref의 경우 랜더링이 되어도 값을 유지한다. 생애주기를 통해 유지되기 때문이다.
- DOM요소에 접근
import { useEffect, useRef } from 'react'
import './App.css';
function App() {
const inputRef = useRef();
useEffect(() => {
console.log(inputRef);
inputRef.current.focus();
}, [])
const loginAlert = () => {
alert(`환영합니다. ${inputRef.current.value}`);
inputRef.current.focus();
}
return (
<div className="App">
<header className="App-header">
<input ref={inputRef} type="text" placeholder="id"/>
<button onClick={loginAlert}>Login</button>
</header>
</div>
);
}
export default App;
페이지가 랜더링될 때 input에 focus가 잘 되게 된다. alert창을 누르고도 input에 계속적으로 focus하게 된다.