리액트를 처음 시작할 때 가장 먼저 배우는 훅은 useState
였다. 상태를 변수처럼 선언하고 상태를 변경하면서 변경된 값으로 컴포넌츠를 렌더링하는 과정이 신기하게 느껴졌다. 특히, 사용법이 크게 어렵지 않았는데 state
로 상태를 선언하고 setState
로 변경할 상태를 인자로 넣어주면 끝이었다.
그 다음에 배운것이 useRef였다. useRef는 HTML DOM을 참조하여 해당 요소 속성을 변경할 때 주로 사용했었다. null로 초기화를 시켜놓고 원하는 요소에 ref 속성으로 해당 요소를 참조하여 속성을 확인할 수 있었다.
기술면접 리스트를 확인하면서 공부하던 와중에 한 가지 질문이 눈에 띄었다.
useState와 useRef의 차이점을 설명하시오
?? 둘은 아예 다른훅이 아니었던가? 너무나 당황스러웠다. 그 동안 공부를 잘 못하고 있던 것 같았다. 하지만, 진짜 면접보기 전에 확인한게 어디인가? 그래서 이번엔 내가 어떠한 부분을 간과하고 있었고 또 어떠한 차이점이 있는지 알아보고 정리해볼 것이다.
내 말은 틀리지는 않았다. 그런데 조금 더 디테일하게 살펴보면서 한가지 키워드가 눈에 띄었다.
set함수에서 내가 간과하고 있던 부분이 눈에 띄었다. 리렌더링을 촉발할 수 있는 함수라는것이다.
Virtual DOM이 해당 상태변화를 감지하고 다시 렌더링하는 점에서 리렌더링이 발생하는데, 이것으로 그동안 화면에 요소값을 바꿀 수 있었다.
import React, { useState } from 'react';
export function App(props) {
const [value, setValue] = useState('');
console.log("리렌더링 발생");
return (
<div className='App'>
<h1>input을 입력하세요</h1>
<input onChange={e => setValue(e.target.value)}></input>
<h2>{value}</h2>
</div>
);
}
input이 change이벤트를 일으킬때마다 set함수를 실행시켜 상태를 변화시키고 변화된 값은 재렌더링을 통해 h2의 값으로 저장되어 화면에 나타난다.
의도했던 완벽한 기능이지만, 문제가 있다. change이벤트 즉, 내가 input의 값을 완성시켰을때가 아니라 변화시킬때마다 재렌더링을 촉발한다는 점이다.
콘솔을 살펴보면 input 값이 변화할때마다 렌더링된다는것을 알 수 있다. 물론 해당 입력하는값이 바뀔때마다 화면에 재렌더링 하고 싶다면 상관없을 수 있지만,
이러한 케이스들을 생각해보면 useState
훅은 좋은 방안이 아닐수도 있다는 생각이 들었다.
useRef
는 그냥 DOM을 참조하는거 아니야? 했던 생각을 바꾸는 문장이 있었는데,
DOM을 참조한다기보다는 어떤 값이든 보유할 수 있는 일반 컨테이너로 개념을 바꿔보자. 그렇다면 useState로 저장한 값을 잠깐 ref에 저장했다가 원할때만 재렌더링 시키면 되지 않을까? 라는생각이 들었다.
import React, { useRef, useState } from 'react';
export function App(props) {
const myRef = useRef(null);
const [value, setValue] = useState("")
console.log("리렌더링 발생");
const valueHandler = () => {
const { current } = myRef;
console.log(current)
setValue(current.value);
}
return (
<div className='App'>
<h1>input을 입력하세요</h1>
<input ref={myRef}></input>
<h2>{value}</h2>
<button onClick={valueHandler}>제출</button>
</div>
);
}
onChange
를 삭제하고 useRef
로 input
을 참조해준다. 그리고 state
의 set함수
를 버튼을 클릭할때 동작하게 만들어준다. 이렇게 되면, myRef
가 input
값을 갖고있고, 버튼을 누를경우 set함수
로 기존 상태를 current.value
로 바꾸어준다.
이렇게 되면 첫번째 렌더링에서 콘솔이 찍히고 버튼을 눌러 set함수
를 실행 시켰을 때 리렌더링이 한번 총 2번의 렌더링이 발생한다.
꼭 useRef
를 써야 정답이 아니라 상황에 맞게 써야하는 것 같다. 말했듯이, 입력도중의 값을 원하거나 입력도중에 화면이 바뀌어야 할 경우에는 useState
가 맞지만, 종료된 시점의 값을 원한다면 useRef로 리렌더링을 방지하면서 최적화를 할 수 있다.