useState
와 useRef
는 리액트에서 컴포넌트 내부의 상태값을 저장하는 변수로 사용된다는대에 동일점을 가지고 있습니다.
하지만 이러한 동일점을 가지고 있어도 그 쓰임새가 다른 만큼 useState를 두고 굳이 useRef가 만들어지지 않았겠죠?
useRef가 useState에 차이점을 두는 주요 부분은 변경에 의한 리렌더링을 발생시키지 않는다는 것
에 그 차이점을 둘 수 있습니다.
import { useState } from 'react'; function Counter() { // useState를 사용하여 count 상태를 선언합니다. const [count, setCount] = useState(0); const onClickButton = (val) => { setCount(count + val) console.log(count) }; return ( <div> <p>Count: {count}</p> <button onClick={() => onClickButton(1)}>Increment</button> <button onClick={() => onClickButton(-1)}>Decrement</button> </div> ); } export default Counter;
위 코드에서는 useState를 이용해 간단한 스테이츠를 하나 만들어 컴포넌트를 제어하는 예제인데요. 위 count에 변화를 주면 이에 따라 페이지가 새로 리렌더링 되는 당연한 결과가 발생합니다.
import { useRef } from 'react'; function Counter() { // useState를 사용하여 count 상태를 선언합니다. const reference = useRef(0) const onClickButton = (val) => { reference.current += val console.log(reference.current); }; return ( <div> <p>reference: {reference.current}</p> <button onClick={() => onClickButton(1)}>Increment</button> <button onClick={() => onClickButton(-1)}>Decrement</button> </div> ); } export default Counter;
반면 useRef의 경우는 다른데, 위의 예제는 useRef를 useState처럼 사용하고자 하는 예제인데요. 그러나 앞서 말씀드린 차이점대로 렌더링이 실시간으로 반영된 useState와는 달리 useRef는 렌더링이 실시간으로 반영이 되지 않는다는 점을 알 수 있습니다.
그래서 리렌더링 분기점을 만들거나, 페이지를 새로고침 할때에야 비로소 리렌더링 되는 모습을 보이는 거죠.
- useState를 사용한 경우
- useRef를 사용한 경우
그리고 또 출력된 콘솔에서 유추해 볼 수 있는 사실은, useState
의 경우 렌더링이 실시간으로 반영된다고 하더라도 실제 useState의 state 값은 이전의 상태값
을 갖고 있는데 반해,
useRef
의 경우 이전의 상태값이 아니라 즉각적인 상태값의 변화를 반영
하고 있기 때문에 앞서 소개해드린 생애 주기에서 자주 사용되는 훅이라는 점도 알 수 있죠.
앞서 소개한 useRef는 또 다른 활용법을 가지고 있는데요. 바로 DOM 요소의 제어에 사용될 수 있다는 점입니다.
import { useState, useRef } from 'react'; function Counter() { // useState를 사용하여 count 상태를 선언합니다. const [count, setCount] = useState(0); // useState를 사용하여 input 필드의 값을 저장합니다. const [inputValue, setInputValue] = useState(''); // useRef를 사용하여 input 요소를 참조합니다. const inputRef = useRef(null); const onClickButton = (val) => { setCount(count + val); }; // 발생한 이벤트의 key가 'Enter', 즉 사용자가 엔터키를 눌렀을 때 const onEnterPress = (e) => { if (e.key === 'Enter') { // 현재 해당 돔 요소를 참조하고 있는 inputRef의 current (DOM)의 value (e.target.value 와 같음)의 값을 inputValue에 대입 setInputValue(inputRef.current.value); } }; return ( <div> <p>Count: {count}</p> <button onClick={() => onClickButton(1)}>Increment</button> <button onClick={() => onClickButton(-1)}>Decrement</button> <input ref={inputRef} type="text" placeholder="Type something" onKeyDown={onEnterPress} /> {/* inputValue의 현재 상태값 출력 */} <p>Input value: {inputValue}</p> </div> ); } export default Counter;
이때 useRef의 활용을 보면 input이라는 DOM 요소를 참조하고 있는 요소로 활용되어 실제 이벤트(Enter)가 발생될 때 참조하고 있는 DOM 요소의 value를 제공하는 역할을 수행하고 있습니다.
이처럼 useRef
는 DOM 요소의 참조를 저장하는 역할로도 활용
될 수 있습니다.