# React useRef 깊은 이해: DOM 접근부터 Fiber 내부 동작까지

React를 사용하다 보면 `useRef`가 “DOM 접근용”으로만 알려져 있지만, 실제로는 렌더 사이에서 값을 유지하거나, 불필요한 렌더를 방지하는 중요한 메커니즘을 담당합니다.  
이번 글에서는 `useRef`가 어떻게 동작하는지, 그리고 그 기반이 되는 **React Fiber 아키텍처**까지 함께 깊이 있게 살펴보겠습니다.

---

# 1\. useRef란 무엇인가?

`useRef`는 다음 값을 반환합니다:

```js
{ current: initialValue }
```

이 객체는 **변경 가능한(mutable)** 객체이며, React는 이 객체를 **Fiber 노드의 hook 구조 내부에 저장**합니다.

즉, `useRef`는 단순한 객체처럼 보이지만 실제로는 React의 내부 렌더링 시스템과 연결된 중요한 Hook입니다.

---

# 2\. useRef는 왜 값이 유지되는가?

React는 컴포넌트마다 **Fiber Node**라는 내부 객체를 유지합니다.  
이 Fiber Node 안에 컴포넌트에 관련된 모든 상태가 저장됩니다:

* state
    
* props
    
* memoized 값
    
* effect
    
* ref
    

`useRef`에서 반환되는 `{ current: ... }` 객체는 이 Fiber Node의 **memoizedState 내부의 Hook 리스트**에 저장됩니다.

렌더링이 다시 일어나도 Fiber Node가 유지되기 때문에  
→ 같은 Hook 위치에 있는 `useRef` 객체도 재사용됩니다.  
→ 따라서 `ref.current` 값이 렌더 사이에서도 계속 유지됩니다.

---

# 3\. useRef 변경은 왜 리렌더링을 발생시키지 않는가?

`useState`는 값이 바뀌면 React의 업데이트 큐에 등록되고 렌더가 다시 발생합니다.  
하지만 `useRef`는 아래처럼 단순한 mutable 값 변경일 뿐입니다:

```js
ref.current = newValue
```

React는 **ref.current 변경을 감지하지 않으며**,  
렌더 트리(Fiber Tree)에 영향을 준다고 판단하지 않습니다.

따라서:

✔ 렌더 발생하지 않음  
✔ 단순한 JavaScript 객체 변경  
✔ React의 의존성 추적(dependency tracking) 시스템 밖에서 움직임

이 점 덕분에 `useRef`는 렌더링 성능을 유지하면서 값을 저장하는 데 매우 적합합니다.

---

# 4\. useRef와 DOM 접근

`useRef`는 렌더 단계에서는 DOM을 알 수 없고,  
**commit 단계에서 React가 실제 DOM 요소를 준비한 뒤** 다음과 같이 값이 할당됩니다:

```less
ref.current = 해당 DOM 노드
```

언마운트 시에는:

```less
ref.current = null
```

이 작업이 commit 단계에서 이뤄지므로 렌더 직후에는 종종 ref가 `null`일 수 있습니다.

---

# 5\. useRef의 실용적인 활용 패턴

### ① DOM 접근

input 포커스, 스크롤 위치 제어 등

### ② 렌더 사이 값 유지

이전 값 저장, 함수 호출 횟수 등

### ③ 타이머 또는 interval ID 보관

debounce / throttle 구현에 필수

### ④ 외부 라이브러리 인스턴스 보관

Map, WebGL 객체, Video.js 등

### ⑤ stale closure 문제 해결

state가 갱신되기 전에 최신 값을 유지해야 하는 경우 매우 유용

---

# 6\. Fiber란 무엇인가?

`useRef`를 깊게 이해하려면 Fiber도 이해해야 합니다.

> **Fiber는 React 컴포넌트 하나를 표현하는 내부 객체이자, React 16에서 도입된 “작업 단위(Work Unit)” 구조입니다.**

즉, Fiber는 React가:

* state
    
* props
    
* hook 목록
    
* 렌더링 작업 상태
    
* 자식/형제 컴포넌트 관계
    
* 이전 렌더의 정보
    

등을 관리하기 위해 사용하는 핵심 단위입니다.

---

# 7\. 왜 Fiber가 필요했을까?

React 15까지는 렌더링이 **중단 불가능**했습니다.

* 렌더 중에는 브라우저 UI가 멈춤
    
* 큰 컴포넌트 트리에서는 프리즈 발생
    
* 사용자 경험 악화
    

React 16의 Fiber 아키텍처는 이를 해결했습니다.

### Fiber로 인해 가능해진 것들

#### ✔ 렌더 중단 + 재개

작업을 잘게 나누고 우선순위에 따라 처리

#### ✔ Concurrent Rendering

사용자 입력 같은 높은 우선순위 작업을 먼저 처리

#### ✔ Suspense & Error Boundary

Fiber Tree 기반으로 특정 컴포넌트 단위 제어 가능

#### ✔ Hook 관리

useState/useEffect/useRef 모두 Fiber의 hook 구조로 구성

---

# 8\. Fiber Node의 구조 예시

실제로는 매우 복잡하지만 핵심 필드를 단순화하면 다음과 같습니다:

```js
FiberNode {
  type,
  pendingProps,
  memoizedProps,
  memoizedState,  // useState, useRef, useEffect 등이 저장됨
  updateQueue,
  child,
  sibling,
  return,
  alternate,      // 이전 렌더의 Fiber
}
```

여기서 `memoizedState` 내부에 hook들이 **단일 연결 리스트(linked list)**로 저장됩니다.

➡ 그래서 Hook은 "호출 순서가 중요"한 것  
➡ 그래서 조건문 안에서 Hook을 호출하면 안 됨

---

# 9\. Fiber와 Virtual DOM의 관계

| **개념** | **역할** |
| --- | --- |
| Virtual DOM | render 결과물 (UI 구조) |
| Fiber | render 작업 단위 + 상태 + 우선순위 + hook 저장 |

Virtual DOM은 UI의 스냅샷이지만  
Fiber는 작업 단위이자 React의 모든 동작의 기반입니다.

---

# 10\. 전체 요약

* `useRef`는 DOM 접근뿐 아니라 렌더 간 값 유지에 사용하는 mutable 객체.
    
* React는 `useRef` 객체를 Fiber의 hook 구조에 저장해 유지한다.
    
* `useRef` 변경은 **리렌더를 발생시키지 않음** → React 의존성 추적 대상이 아님.
    
* DOM ref는 commit 단계에서 설정된다.
    
* Fiber는 React가 렌더링을 중단·재개·우선순위 처리하기 위해 도입한 핵심 구조.
    
* Fiber 안에 hook 정보(useRef, useState 등)가 저장되므로 렌더 사이 값이 유지됨.
    

---

# 마무리

React의 렌더링 최적화와 hook 시스템은 **Fiber 아키텍처** 위에서 돌아갑니다.  
`useRef`는 단순한 DOM 접근 도구가 아니라, Fiber 구조 내부에서 **렌더와 독립적으로 움직이는 mutable 캐시**입니다.

이 개념을 이해하면:

* 불필요한 렌더 방지
    
* stale closure 문제 해결
    
* 고급 상태 관리 패턴 설계
    
* 성능 최적화
    

등에 큰 도움이 됩니다.  

---

### **🧾 작성 참고**

> ***이 글은 ChatGPT의 도움을 받아 내용을 정리하였습니다.***
