안녕하세요 YB 문혜성입니다!
이번에 React의 리렌더링에 대해 더 찾아보다가 자연스럽게 useEffect에 대한 궁금증이 생겼고, 그 과정에서 이 주제를 다뤄보고 싶다는 생각이 들었습니다.
또한, 세미나에서 Virtual DOM과 리렌더링 구조를 배우며 단순히 Hook 문법을 외우는 것보다 React의 작동 원리를 이해하는 것이 더 중요하다는 걸 느꼈어요.
따라서 이번 글에서는 useEffect가 언제 실행되는지, 왜 반복되는지, 그리고 어떻게 올바르게 사용하는지를 정리해보려고 합니다😊
🧠 Virtual DOM과 리렌더링 구조
React는 Virtual DOM을 사용하여 효율적인 렌더링을 구현합니다. 상태가 변경되면 새로운 Virtual DOM이 생성되고, 이전 Virtual DOM과 비교하여 변경된 부분만 실제 DOM에 반영됩니다.
이 다이어그램은 Virtual DOM의 구조와 실제 DOM과의 관계를 보여줍니다. 상태 변경 시 새로운 Virtual DOM이 생성되고, 이전 Virtual DOM과의 차이를 비교하여 변경된 부분만 실제 DOM에 반영하는 과정을 시각적으로 이해할 수 있습니다
🔍 React의 렌더링 구조 간단 요약
우리가 상태(state)를 바꾸면 React는 다음 순서로 화면을 업데이트해요.
<img src="스크린샷1.png" alt="Virtual DOM 리렌더링 설명" />
- 상태(state)가 변경되면
- 새로운 Virtual DOM이 생성되고
- 이전 Virtual DOM과 비교해 바뀐 부분만 찾아
- 실제 DOM에 반영해 렌더링합니다
이 과정을 최적화하기 위해 React는 Render Phase와 Commit Phase라는 두 단계로 렌더링을 나눠요.
- Render Phase: 어떤 부분이 바뀌었는지 계산
- Commit Phase: 실제로 브라우저에 반영
이제 여기서 중요한 건… 바로 useEffect는 렌더링 "이후"에 실행된다는 거예요.
📌 useEffect란?
useEffect는 **React 함수형 컴포넌트에서 side effect(부수 효과)**를 처리할 때 사용하는 Hook이에요.
이벤트 리스너 등록, 타이머 설정, API 호출처럼 컴포넌트가 렌더링된 후에 실행되어야 하는 작업을 담당합니다.
이 다이어그램은 React 컴포넌트의 생명주기에서 useEffect가 언제 실행되는지를 보여줍니다. 렌더링 후에 사이드 이펙트가 실행되며, 의존성 배열에 따라 실행 여부가 결정돼요!
⚠️ 흔한 실수: 무한 렌더링
useEffect 내부에서 상태를 변경하면 무한 렌더링이 발생할 수 있습니다. 이를 방지하기 위해 의존성 배열을 적절히 설정해야 합니다.
❌ 잘못된 예시
import { useEffect, useState } from 'react';
function CountInputChanges() {
const [value, setValue] = useState('');
const [count, setCount] = useState(-1);
useEffect(() => setCount(count + 1));
const onChange = ({ target }) => setValue(target.value);
return (
<div>
<input type="text" value={value} onChange={onChange} />
<div>Number of changes: {count}</div>
</div>
)
}
위의 코드는 변경이 의존성 배열에 포함되지 않아 무한 루프가 발생하는 예시를 보여줍니다. 이를 해결하기 위해서는 어떻게 해야할까요?
✅ 올바른 예시
import { useEffect, useState } from 'react';
function CountInputChanges() {
const [value, setValue] = useState('');
const [count, setCount] = useState(-1);
useEffect(() => setCount(count + 1), [value]);
const onChange = ({ target }) => setValue(target.value);
return (
<div>
<input type="text" value={value} onChange={onChange} />
<div>Number of changes: {count}</div>
</div>
);
}
이렇게 [value]를 의존성 배열로 설정하면, value가 변경될 때만 useEffect가 실행되어 무한 렌더링을 방지할 수 있어요!
💡 실전에서 기억할 팁
- useEffect는 렌더링이 끝난 후 실행됨
- 의존성 배열을 정확히 설정해야 불필요한 재실행을 방지할 수 있음
- 상태 변경 함수(setState)를 useEffect 내부에 둘 땐 반드시 조건문으로 제어하거나 의존성 배열을 적절히 조정
- 렌더링 구조 (Virtual DOM → diff → Commit)와 useEffect 실행 흐름을 연결해서 이해하면 실수가 줄어듦
💭 마무리하며
이번 세미나에서 배운 Virtual DOM 개념과 렌더링 구조는 단순히 성능 최적화의 개념이 아니라, useEffect와 같은 Hook을 정확히 이해하기 위한 핵심 기반이라는 걸 느꼈어요.
React는 렌더링을 효율적으로 해주지만, 렌더링 시점과 그 이후 실행되는 로직을 잘 구분해서 작성하는 건 개발자의 몫이에요.
혹시 여러분도 useEffect를 사용할 때 헷갈렸던 경험이 있으셨다면, 이 글이 작은 도움이라도 되었기를 바랍니다. 🙌
출처: https://blog.kohinoornimes.tech/react-fundamentals, https://github.com/donavon/hook-flow, How to Solve the Infinite Loop of React.useEffect()
'2주차' 카테고리의 다른 글
협업과 정확성을 위한 주석 JSDoc (0) | 2025.04.23 |
---|---|
SPA (Single Page Application) (0) | 2025.04.21 |
JavaScript 프론트엔드 면접 개념 정리 & 자주 나오는 질문 모음집 (0) | 2025.04.15 |
스코프에 대하여(scope) (0) | 2025.04.15 |
CSR vs SSR 정확히 집고 넘어가자 (0) | 2025.04.14 |