


렌더링은 언제 발생하는가
— React가 다시 그리기로 결정하는 정확한 순간들
지난 글에서 핵심 공식을 하나 남겼다.
UI = f(state)
이번 글에서는 이 질문을 끝까지 판다.
React는 정확히 언제, 어떤 조건에서 다시 렌더링을 하는가?
이걸 모르면
- “왜 여기서 렌더가 되지?”
- “왜 이 컴포넌트는 안 바뀌지?”
- “왜 성능이 터지지?”
같은 질문을 평생 반복하게 된다.
1️⃣ React 렌더링의 정확한 정의
먼저 용어부터 정리한다.
실무에서 가장 많이 헷갈리는 부분이다.
React에서 말하는 “렌더링”이란
컴포넌트 함수가 다시 실행되어 JSX를 다시 계산하는 것
❌ DOM에 바로 그리는 것
❌ 화면이 실제로 바뀌는 것
⭕ 함수 실행
⭕ Virtual DOM 트리 생성
function Counter({ count }) {
console.log("렌더링 발생");
return <div>{count}</div>;
}
위 코드에서 console.log가 찍히면
→ 렌더링은 이미 발생한 상태다.
DOM 반영은 그 다음 단계다.
2️⃣ 렌더링을 발생시키는 3가지 트리거 (실무 핵심)
React에서 렌더링을 유발하는 건 딱 세 가지다.
① state 변경
const [count, setCount] = useState(0);
setCount(1);
- 가장 흔함
- 값이 같아도 setState가 호출되면 렌더 후보가 된다
(단, Object.is 비교로 bail-out 되는 경우 있음)
② props 변경
<Child value={count} />
- 부모가 렌더링되면
- 자식은 props 비교 후 렌더 여부 판단
👉 그래서 “부모 렌더 = 자식 렌더”처럼 느껴진다.
③ context 값 변경
const ThemeContext = createContext();
<ThemeContext.Provider value={theme}>
- Provider의 value가 바뀌면
- 해당 context를 구독 중인 모든 컴포넌트가 렌더 후보
👉 전역 상태 남용이 위험한 이유다.
3️⃣ 렌더링 ≠ DOM 업데이트 (아주 중요)
이 코드를 보자.
function App() {
const [count, setCount] = useState(0); // 구조분해할당 return [stateValue, setStateFunction]
console.log("App 렌더");
return (
<>
<button onClick={() => setCount(count)}>증가</button>
<div>{count}</div>
</>
);
}
버튼을 눌러도 로그는 찍힌다.
하지만 화면은 안 바뀐다.
왜?
- 렌더링은 발생했지만
- 이전 결과와 새 결과가 같아서
- DOM 업데이트 단계에서 스킵되기 때문이다
👉 React는
렌더링과 커밋(commit)을 분리해서 생각해야 한다.
4️⃣ 부모 렌더링은 왜 자식을 흔드나
실무에서 가장 많이 터지는 오해다.
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(c => c + 1)}>+</button>
<Child />
</>
);
}
function Child() {
console.log("Child 렌더");
return <div>자식</div>;
}
버튼을 누르면 Child 렌더가 찍힌다.
이유는 단순하다.
- Parent 함수가 다시 실행됨
- JSX를 다시 만들면서 <Child />도 다시 평가됨
- Child 함수도 실행됨
👉 부모 렌더 → 자식 렌더는 기본 동작이다.
5️⃣ 그럼 React.memo는 뭘 막는가
const Child = React.memo(function Child() {
console.log("Child 렌더");
return <div>자식</div>;
});
이제 버튼을 눌러도 로그가 안 찍힌다.
React.memo는
- props가 바뀌지 않으면
- 자식 렌더링을 스킵한다
여기서 중요한 점.
React.memo는 “렌더링 최적화 도구”이지
“상태 관리 도구”가 아니다.
남용하면 구조 이해가 더 어려워진다.
6️⃣ useEffect는 렌더링 이후에 실행된다
이 순서를 정확히 기억해야 한다.
- state/props 변경
- 컴포넌트 함수 실행 (렌더링)
- DOM 반영
- useEffect 실행
useEffect(() => {
console.log("effect 실행");
}, [count]);
그래서 이런 코드는 위험하다.
useEffect(() => {
setCount(count + 1);
}, [count]);
👉 렌더 → effect → setState → 렌더
👉 무한 루프의 전형적인 시작점
7️⃣ 실무 기준으로 기억해야 할 한 문장
이 문장 하나면 렌더링 사고가 정리된다.
React는 상태 변경이 감지되면
전체 컴포넌트 트리를 다시 계산하고,
바뀐 부분만 DOM에 반영한다
그래서 우리가 해야 할 일은 단 하나다.
- 렌더링을 막으려 하지 말고
- 렌더링이 싸도록 구조를 만든다
다음 글 예고
다음 글에서는 이 질문으로 간다.
👉 “useEffect는 왜 위험한가”
- 왜 side effect가 렌더링 사고를 만든다 말하는지
- 어떤 effect는 써도 되고
- 어떤 effect는 구조가 잘못된 신호인지
실무에서 가장 많이 터지는 지점을
코드로 하나씩 해부해볼 예정이다.
'framework_library > react' 카테고리의 다른 글
| Context / Zustand / Redux (0) | 2026.01.10 |
|---|---|
| 전역 상태는 왜 마지막 카드인가 (0) | 2026.01.10 |
| 상태는 어디에 둬야 하는가 (1) | 2026.01.09 |
| useEffect는 왜 위험한가 (0) | 2026.01.09 |
| 상태(State)로 UI를 설계하는 사고방식 (0) | 2025.04.08 |
댓글