많은 React 개발자들은 “리렌더링을 막아야 성능이 좋아진다”는 말로 시작하지만,
실제로 애플리케이션을 느리게 만드는 건 리렌더링 그 자체가 아니라 “느린 렌더링”입니다.
리액트 프로젝트를 하다 보면 이런 말을 자주 듣습니다.
“리렌더링이 너무 많아요.”
“useCallback으로 막아야 해요.”
하지만 정말 리렌더링 자체가 성능 문제일까요?
이 글에서는 Kent C. Dodds의 글 Fix the slow render before you fix the re-render
의 핵심 내용을 바탕으로,Virtual DOM의 본질과 리렌더링에 대한 오해를 정리해봅니다.
React의 Virtual DOM은 종종 “렌더링을 캐싱해서 줄여주는 기술”로 오해됩니다.
하지만 그 목적은 명확합니다.
“DOM 업데이트를 묶어서 효율적으로 커밋(batch commit)하기 위한 기술.”
DOM 조작은 느립니다.
그래서 React는 여러 변경을 메모리 상에서 Virtual DOM 트리로 계산(diff) 한 뒤,
실제 DOM에는 필요한 최소한의 변경만 한 번에 커밋(commit) 합니다.
즉, 렌더링(render)이 여러 번 일어나더라도
커밋(commit)이 한 번만 일어나면 성능에 큰 영향이 없습니다.
React는 상태가 바뀔 때 다음의 단계를 거칩니다.
render → reconciliation → commit
↖ ↙
state change
Render 단계
JSX를 React Element로 변환하는 순수 계산 단계입니다.
DOM을 직접 수정하지 않습니다.
Reconciliation 단계
이전 Virtual DOM과 새 Virtual DOM을 비교(diff)합니다.
Commit 단계
변경이 필요한 부분만 실제 DOM에 반영합니다.
브라우저의 repaint/reflow가 이때 발생합니다.
느린 구간은 렌더가 아니라 commit 단계입니다.
따라서 “렌더링이 많다 = 느리다”는 잘못된 인과입니다.
Kent C. Dodds가 인용한 이 영상은
리렌더링과 DOM 업데이트의 차이를 한눈에 보여줍니다.
Look how many React components re-render when we open a "Tweet" modal, yet how few browser repaints are happening.
— @asidorenko_
Chrome DevTools의 “Highlight Updates” 기능을 켜면
“Tweet 작성 모달”을 열 때 수많은 컴포넌트가 번쩍이며 리렌더링되는 걸 볼 수 있습니다.
하지만 동시에 “Paint Flashing” 기능으로 확인하면
실제 브라우저 repaint는 화면 일부에서만 발생합니다.
💡 React render ≠ DOM update
리렌더링이 여러 번 일어나도, Virtual DOM이 diff를 계산해
결국 실제로 DOM이 변경되는 부분은 극히 일부입니다.
렌더(render)는 React가 UI를 계산하는 순수 함수입니다.
대부분의 경우 이 계산은 매우 빠르며,
Virtual DOM의 diff 알고리즘 덕분에 DOM에 손대지 않는 한 성능 저하는 거의 없습니다.
진짜 문제는 “렌더링 중 실행되는 코드”입니다.
// 무거운 계산
{items.map(item => heavyCalculation(item))}
// 렌더 중 데이터 변환
const result = data
.filter(expensiveFilter)
.map(expensiveTransform)
.reduce(expensiveReducer);
이런 경우는 useCallback이 아니라
React Profiler를 사용해 병목 구간을 찾는 것이 올바른 접근입니다.
“Fix the slow render before you fix the re-render.”
— Kent C. Dodds
즉, 리렌더링을 줄이기 전에, 느린 렌더링을 먼저 고쳐야 합니다.
렌더링이 느리면 “얼마나 자주 리렌더되느냐”보다
“한 번의 렌더링에 얼마나 많은 일을 하느냐”가 훨씬 더 중요합니다.
원문: Fix the slow render before you fix the re-render
작성일: September 9th, 2019 — 7 min read
by Pascal van de Vendel, published on Kent C. Dodds’ blog
핵심 요약
React의 Virtual DOM은 DOM 업데이트를 일괄 커밋(batch) 하기 위한 구조다.
렌더(render)는 함수 호출이며, DOM 업데이트와 직접적인 관련이 없다.
불필요한 리렌더링이 발생해도, DOM이 업데이트되지 않으면 성능 문제는 거의 없다.
성능 문제의 대부분은 렌더링 중 무거운 계산, 데이터 변환, 비효율적인 코드 때문이다.
리렌더링을 줄이려 하기보다, 렌더링 자체가 빠르도록 개선하는 게 먼저다.
Chrome DevTools와 React Profiler를 활용해 느린 구간을 측정 후 수정하라.
“Stop punching yourself in the face every time you blink.
Fix your slow renders first.”
— Kent C. Dodds
| 구분 | 잘못된 오해 | 올바른 이해 |
|---|---|---|
| Virtual DOM | 렌더링을 줄이기 위한 캐시 | DOM 업데이트를 효율적으로 커밋하기 위한 기술 |
| 리렌더링 | 많으면 느리다 | 많아도 빠를 수 있다 — commit이 핵심 |
| 최적화 | useCallback으로 막기 | Profiler로 병목 원인 찾기 |
| 성능 목표 | 렌더링 횟수 줄이기 | 렌더당 비용 줄이기 |
리렌더링은 React가 UI를 유지하기 위해 거치는 자연스러운 과정입니다.
중요한 것은 “얼마나 자주 리렌더되느냐”가 아니라
“한 번의 렌더가 얼마나 가볍게 수행되느냐”입니다.
Virtual DOM은 “덜 렌더링하기”가 아니라
“더 똑똑하게 커밋하기” 위한 기술입니다.
🔍 “리렌더링이 문제인가?”
아니면
“렌더링 중 실행되는 코드가 문제인가?”
성능이 느릴 때, 이 질문부터 시작하세요.
그게 진짜 React 최적화의 출발점입니다.
Fix the slow render before you fix the re-render (Kent C. Dodds)
AHA Programming — Kent C. Dodds
트위터 예시 영상