useRef란?
useRef는 저장공간(변수 관리), DOM 요소에 접근을 위해 사용이 되는 React hooks입니다. useRef는 useState와 동일하게 컴포넌트 내부에서 렌더링이 일어나도 변경 가능한 상태값을 저장한다는 공통점이 있습니다. 그러나, useState와 구별되는 큰 차이점 두 가지를 가지고 있습니다.
- useRef는 반환값인 객체 내부에 있는 current로 값에 접근 또는 변경할 수 있습니다.
- useRef는 그 값이 변하더라도 렌더링을 발생시키지 않습니다.
useRef에 대해 본격적으로 알아보기 전에 왜 useRef가 필요한지 먼저 고민해봅시다.
렌더링에 영향을 미치지 않는 고정된 값을 관리하기 위해서 useRef를 사용한다면 useRef를 사용하지 않고 그냥 함수 외부에서 값을 선언해서 관리하는 것도 동일한 기능을 수행할 수도 있지 않을까요? 다음 예제를 보겠습니다.
let value = 0;
function Component() {
function handleClick() {
value += 1;
}
// ....
}
위의 코드는 결론부터 이야기하자면 단점이 2가지 있습니다.
첫 번째로 컴포넌트가 실행되어 렌더링되지 않았음에도 value라는 값이 기본적으로 존재하게 됩니다. 이는 메모리에 불필요한 값을 갖게 하는 악영향을 미칩니다. 두 번째로 만약 Component, 즉 컴포넌트가 여러 번 생성된다면 각 컴포넌트에서 가리키는 값이 모두 value로 동일합니다. 컴포넌트가 초기화되는 지점이 다르더라도 하나의 값을 봐야 하는 경우라면 유효할 수도 있지만 대부분의 경우에는 컴포넌트 인스턴스 하나당 하나의 값을 필요로 하는 것이 일반적입니다.
useRef는 앞서 언급한 두 가지 문제를 모두 극복할 수 있는 리액트식 접근법입니다. 컴포넌트가 렌더링될 때만 생성되며, 컴포넌트 인스턴스가 여러 개라도 가각 별개의 값을 바라봅니다.이제 useRef의 일반적인 예제를 같이 보면서 살펴보겠습니다.
1. 저장공간(변수 관리)
저장공간이라 하면 보통 State가 떠올를 텐데 State의 값을 바꿀 때 대표적으로 hooks의 useState를 이용합니다.
React 컴포넌트는 State가 변할 때마다 다시 렌더링이 되면서 컴포넌트 내부 변수들이 초기화가 됩니다. 컴포넌트 내부 변수들이 초기화가 된다는 것은 해당 컴포넌트 함수의 변수들이 모두 초기화가 되고 모든 함수 로직 등이 다시 실행되는 것을 의미합니다. 이렇게 원하지 않는 렌더링 때문에 곤란할 때가 있습니다. 그렇다면 State대신 Ref안에 값을 저장하면 어떻게 될까요? Ref의 유용한 점은 Ref안에 있는 값을 아무리 변경해도 컴포넌트는 다시 렌더링 되지 않습니다. 즉, State 대신 Ref를 사용한다면 불필요한 렌더링을 막을 수 있습니다. 또한 컴포넌트가 아무리 렌더링이 되어도 Ref안에 저장되어 있는 값은 변화되지 않고 그대로 유지가 됩니다. 그렇기 때문에 변경 시 렌더링을 발생시키지 말아야 하는 값을 다룰 때 정말 편리합니다.
State의 변화 ➡️ 렌더링 ➡️ 컴포넌트 내부 변수들 초기화
Ref의 변화 ➡️ No 렌더링 ➡️ 변수들의 값이 유지됨
State의 변화 ➡️ 렌더링 ➡️ 그래도 Ref의 값은 유지됨
useRef를 이용하여 컴포넌트가 아무리 렌더링이 되어도 Ref안에 저장되어 있는 값은 변화되지 않고 그대로 유지가 되는지 확인하는 예제입니다. 즉, 상태 관리를 어떻게 하는지 확인해보도록 하겠습니다.
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;
실행 화면
Ref Up과 Var Up 버튼을 클릭하면 콘솔에 각각의 값들이 증가하는 것을 확인할 수 있습니다. 하지만, Render 버튼을 클릭하지 않으면 화면에 업데이트가 되지 않습니다. Ref의 값이 5이고 Var의 값이 4일 때 Render버튼을 클릭하였는데 화면에 Ref는 5가 잘 표시되었지만, Var는 0으로 표시되었습니다. 렌더링이 될 때마다 컴포넌트 함수 내부에 있는 변수들이 다시 초기화가 되어 Var의 값은 0이 됩니다. 하지만, Ref는 다릅니다. 아무리 컴포넌트가 렌더링이 되어도 계속 값을 유지합니다. 왜냐하면 Ref의 값은 컴포넌트의 전 생애주기를 통해 유지되기 때문입니다. 컴포넌트가 브라우저의 마운팅 된 시점부터 마운트 해제될 때까지 같은 값을 계속해서 유지할 수 있다는 뜻입니다.
2. DOM 요소에 접근
대표적으로는 input요소를 클릭하지 않고 포커스를 주고 싶을 때 많이 사용됩니다. 예를 들어, 로그인 화면이 보여줬을 때 id를 넣는 Input을 굳이 클릭하지 않아도 자동적으로 포커스가 되어 있게 해 주면 바로 키보드를 입력해서 id를 입력할 수 있어 굉장히 편리할 수 있습니다. 바닐라 자바스크립트의 document.querySelector()와 비슷하다고 생각하시면 됩니다.
로그인 화면이 보여줬을 때 id를 넣는 Input을 굳이 클릭하지 않아도 자동적으로 포커스가 되어 있게 해 주면 바로 키보드를 입력해서 id를 입력할 수 있도록 하는 예제입니다.
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;
실행 화면
페이지가 렌더링 될 때도 id input창에 포커스가 잘 되어 있고, 환영한다는 앨럿의 확인을 누르고 난 뒤에도 input으로 포커스가 잘 된 것을 확인하실 수 있습니다.
Reference
react.org-hooks-useRef
[React] useRef() 여러 개를 한 개로 관리하기
'1. 웹개발 > 1_1_5 React JS' 카테고리의 다른 글
[React] useMemo 사용법 및 예제 (0) | 2022.04.06 |
---|---|
[React] useContext 사용법 및 예제 (0) | 2022.04.04 |
[React] useEffect란? (0) | 2022.03.25 |
[React] useState란? (0) | 2022.03.18 |
[React] 리덕스 총정리 및 예제 (0) | 2022.03.13 |