렌더링이란 무엇인가?
리액트에서 "렌더링"이란 컴포넌트가 현재 props와 state를 바탕으로 UI를 계산하는 과정입니다.
- 컴포넌트 함수를 호출한다.
- JSX를 반환한다.
- JSX를 React 엘리먼트로 변환한다.
식당으로 비유해 쉽게 설명하면:
- UI: 손님이 먹을 음식
- 컴포넌트: 주방장 (음식을 만드는 사람)
- 리액트: 웨이터 (주문을 받고 요리를 전달함)
- Triggering (렌더링 유발): 손님이 새 음식을 주문한다 (state 변경, props 변경 등)
- Rendering (렌더링 과정): 주방장이 새 음식을 만든다 (컴포넌트 함수 호출 → JSX 반환)
- Commit (커밋 과정): 웨이터가 완성된 음식을 손님 테이블에 가져다 놓는다 (DOM 업데이트)
렌더링은 언제 발생하는가?
- 앱이 처음 실행될 때: 처음 화면을 만들 때
- state가 변경될 때: 컴포넌트 내부의 상태가 바뀔 때
- props가 변경될 때: 부모 컴포넌트가 다른 값을 줄 때
- 부모 컴포넌트가 다시 렌더링될 때: 부모가 렌더링되면 자식도 기본적으로 함께 호출됨
- 공유 값(context)이 바뀔 때: Provider의 값이 바뀌면 그 값을 사용하는 하위 컴포넌트들도 다시 렌더링됨
Re-render, 리렌더링
컴포넌트 상태가 바뀌면 리렌더링이 발생합니다. 여러 상태가 한 번에 변경되면 리액트는 이를 큐에 넣어 순서대로 처리합니다.
- 손님이 첫 주문 후 갈증이 나 음료를 추가로 주문하거나 음식이 마음에 들지 않아 새 메뉴를 다시 주문하는 상황이 리렌더링입니다.
- 새 주문이 들어오면 리액트가 변경 내용을 주방의 요리사(컴포넌트)에게 전달합니다. 요리사는 이 변경된 주문을 바탕으로 새 음식을 준비합니다. (컴포넌트 함수 호출 → 새로운 UI 생성)
- 완성된 새 요리는 웨이터(리액트)를 통해 손님 테이블에 올라갑니다. (DOM 반영 → 커밋 단계)
📝상태 업데이트는 순서대로 큐에 쌓이지만 렌더링은 한 번에 묶어서 실행됩니다.
- 상태가 바뀔 때마다 바로 렌더링하지 않고 리액트는 내부적으로 업데이트 요청을 큐에 차례로 저장합니다.
- 이벤트 루프가 끝나기 전까지 여러 업데이트를 모아 두었다 한 번에 렌더링을 수행합니다. -> 배칭(Batching)
- 업데이트 순서는 보장되며 렌더링 횟수는 최소화 됩니다.
다시 식당으로 비유해 보자면:
- 손님이 3번에 걸쳐 추가 주문을 함 (음식 추가, 음료 추가, 디저트 추가)
- 웨이터는 주문이 들어올 때마다 계산서에 차례대로 적어 놓음 (순서 보장)
- 주방엔 한 번에 묶어서 넘김 → 주방장은 한 번에 전체 주문 처리.
⚠️브라우저 렌더링과 리액트의 렌더링은 다릅니다!
리액트가 렌더링을 마치고 DOM을 업데이트하면 그 다음에 브라우저가 화면에 실제로 그림을 그립니다.
이 과정을 브라우저 렌더링이라고 부르지만 혼동을 피하기 위해 페인팅(Painting)이라고도 합니다.
컴포넌트 함수 호출 → 가상 DOM 생성 → 차이 비교 → 실제 DOM 반영 → 브라우저가 화면 그리기
그럼 리렌더링을 무조건 줄이는 게 좋을까?
결론부터 얘기하면
불필요한 리렌더링은 줄여야 하지만 리렌더링 자체를 너무 두려워할 필요는 없다!
🧠 React의 렌더링은 생각보다 빠르다
React는 내부적으로 Virtual DOM + Diffing 알고리즘을 사용해서 최소한의 변경만 실제 DOM에 반영 합니다.(렌더링 = DOM 조작이 아님) 때문에 단순한 리렌더링은 비용이 크지 않습니다.
- 단순하고 가벼운 컴포넌트: 거의 부담 없음
- UI 조각 일부만 변경될 때: Virtual DOM 최적화로 리액트가 잘 처리해줌
이런 경우에는 리렌더링을 굳이 걱정할 필요가 없습니다.
다만 다음과 같은 경우에는 리렌더링을 줄이는 것이 좋습니다:
- 복잡하고 무거운 컴포넌트: 렌더링 자체가 무겁기 때문에 불필요한 호출이 쌓이면 성능에 영향을 준다.
- 데이터가 많은 리스트, 표, 차트: 일부 데이터만 변경돼도 전체가 다시 렌더링되면 낭비가 크다.
- 자주 열리고 닫히는 UI (예: 모달, 토글 등): 상태 변화가 반복되면서 매번 렌더링이 발생할 수 있다.
- 부모 state 변경이 자식까지 전파될 때: 꼭 변경이 필요 없는 자식 컴포넌트까지 불필요하게 호출되는 경우가 있다.
렌더링을 줄이려면?
기술 | 설명 |
React.memo | props가 같으면 컴포넌트 호출을 생략 |
useCallback, useMemo | 함수나 계산값을 기억해서 불필요한 렌더링 방지 |
useTransition, useDeferredValue | (React 18) 렌더링 부담이 큰 작업을 나눠서 천천히 처리 |
key 최적화 | 리스트에서 key가 바뀌지 않게 유지하면 기존 DOM을 재사용할 수 있음 |
상태 쪼개기 | 꼭 필요한 컴포넌트만 리렌더링되도록 구성한다. (상태를 불필요하게 상위 컴포넌트에 두지 말 최대한 필요한 컴포넌트 가까이에 두자) |
'기술 > React.js' 카테고리의 다른 글
React가 빠른 이유: Virtual DOM, Diffing, Reconciliation, Batch Update 이해하기 (0) | 2025.06.18 |
---|---|
리액트의 특징에 대해 알아보자 (2) | 2025.06.18 |
[문서] 리액트 공식문서 톱아보기: 컴포넌트를 순수하게 유지하자 (1) | 2025.05.06 |
[문서] 리액트 공식문서 톱아보기: 컴포넌트 import 및 export (1) | 2024.11.16 |
[문서] 리액트 공식문서 톱아보기: 리액트에서 key가 중요한 이유는? (5) | 2024.11.06 |