
React에서 값을 저장할 때 let 변수, useState, useRef 중 무엇을 사용해야 할까?
이 글에서는 다음 세 가지를 명확히 정리한다.
- 왜 컴포넌트 내부에 선언된 let 변수는 리렌더링 시 초기화되는가
- useState와 useRef는 왜 값이 유지되는가
- useState와 useRef의 근본적인 차이
1. 리렌더링과 함수 재실행
React 컴포넌트는 함수이다.
function Register() {
let count = 0;
return <div />;
}
상태가 변경되면 해당 컴포넌트 함수는 다시 실행된다.
따라서 함수 내부의 let 변수는 렌더링마다 다시 선언되고 초기화된다.
- let count 변수 → 렌더링마다 초기화
- 렌더링과 독립적인 저장 공간이 아님
2. useState와 useRef가 값이 유지되는 이유
const [count, setCount] = useState(0);
const countRef = useRef(0);
이 코드도 렌더링마다 실행된다. 하지만 값은 유지된다.
이유는 useState와 useRef가 React 내부 저장소(Fiber)에 연결되기 때문이다.
이건 다음 포스트에서 살펴볼 예정~
React는 컴포넌트 인스턴스마다 훅 데이터를 별도로 관리한다.
따라서:
- 컴포넌트가 다시 실행되어도
- React가 이전 값을 그대로 반환한다
중요한 개념:
리렌더링은 함수를 다시 실행하는 것이지, React의 훅 저장소를 초기화하는 것이 아니다.
3. 파일 전역 변수와의 차이
// 파일 전역
let count = 0;
예를들어서 Register 컴포넌트에서는 위에 전역 변수 count를 공유해서 사용한다고 해보자.
이 경우 값은 유지되지만 문제가 있다.
<Register />
<Register />
두 개의 Register 컴포넌트가 같은 count를 공유하게 된다. 각각의 컴포넌트 마다 독립된 그 누적 count를 사용하고자 선언했지만 예기치 못한 상황이 발생되는 것임.
그러나!
useState와 useRef는 컴포넌트 인스턴스별로 저장 공간이 분리된다.
| 방식 | 저장 위치 | 인스턴스 분리 |
|---|---|---|
| 파일 전역 let | JS 모듈 스코프 | ❌ 공유됨 |
| useState | React Fiber | ✅ 분리됨 |
| useRef | React Fiber | ✅ 분리됨 |
4. useState와 useRef의 근본적인 차이
useState
setCount(prev => prev + 1);
- 값 변경 시 리렌더링 발생
- UI 자동 업데이트
- 화면에 반영되는 상태 관리용
상태가 무엇일까.. 말그대로 상태다.
상태(state)가 변하면 -> React가 감지한다. -> 해당 state의 컴포넌트(함수)를 다시 실행한다 -> 화면이 업데이트되어 다시 그려진다.
어디에 활용할 수 있을까?
function Game() {
const [hp, setHp] = useState(100);
return (
<div>
<h1>HP: {hp}</h1>
<button onClick={() => setHp(hp - 10)}>공격 받기</button>
</div>
);
}
예를들어 버튼을 누를 때마다 체력이 깎이는 상황을 만들 수 있는데, 버튼을 누를 때 state가 변경됨으로 hp가 계속해서 줄어드는 그런 새로운 UI를 볼 수 있다.
간단하다. "이벤트"에 따라서 새로운 UI를 그린다.
여기서의 이벤트는 공격 받기 이벤트다.
function Light() {
const [isOn, setIsOn] = useState(false);
return (
<div>
<h1>{isOn ? "💡 켜짐" : "🌑 꺼짐"}</h1>
<button onClick={() => setIsOn(!isOn)}>
스위치 누르기
</button>
</div>
);
}
전구에서 전등을 예로들 수 있다.
스위치를 누르면, 전구가 켜지는 UI를 보여줄 수 있고, 꺼지면 전구가 꺼진 UI를 화면에 보여줄 수 있다.
1. 처음에 false (꺼짐)
2. 버튼 클릭(이벤트 발생 !!!!! )
3. setIsOn(true) -> state(isOn) 는 true가 됨
4. React가 변화된 state를 감지해서 자동으로 다시 그림(리렌더링)
5. 화면이 켜짐UI로 변경
useRef
countRef.current += 1;
- 값 변경 시 리렌더링 없음
- UI 자동 반영 없음
- 렌더와 무관한 값 저장
5. useRef의 주요 사용 사례
1) 렌더와 무관한 값 저장
- 수정 횟수 기록
- 이전 값 보관
- 타이머 ID 저장
- 스크롤 위치 저장
2) DOM 요소 직접 참조
const inputRef = useRef(null);
<input ref={inputRef} />
inputRef.current.focus();
useRef는 실제 DOM 노드를 직접 제어할 수 있는 통로를 제공한다.
결론
- let 변수는 리렌더링 시 초기화된다.
- useState와 useRef는 React 내부 저장소에 연결된다.
- useState는 UI 상태를 위한 도구이다.
- useRef는 리렌더와 무관한 값 및 DOM 제어용 도구이다.