useEffect는 언제 실행될까? - React SSR과 Hydration 타이밍

SilverAsh·2025년 11월 4일
0

React

목록 보기
3/5

React의 useStateuseEffect와 달리 렌더링 시점부터 관여하는 훨씬 앞단의 훅이다.
그래서 SSR·Hydration 흐름 속에서 언제, 어디서, 어떻게 초기화되는지를 정확히 이해하면 Hydration-safe 코드를 작성할 때 훨씬 감이 잡힌다.


useState는 렌더 단계에서 실행된다

React는 컴포넌트를 렌더링할 때 다음과 같은 과정을 거친다.

단계설명
1컴포넌트 함수를 실행해서 JSX를 얻는다.
2그 안에서 useState()가 호출되면, React는 내부적으로 상태 저장소를 만든다.
3JSX 결과를 가상 DOM(Fiber Tree)에 저장하고, 실제 DOM으로 반영한다.

즉, useState의 초기값은 렌더링 시점에 바로 평가(evaluate) 된다.

function Example() {
  const [count, setCount] = useState(0); // ← 여기서 이미 실행됨
  console.log("렌더링 중!");
  return <div>{count}</div>;
}

서버든 클라이언트든, React가 이 컴포넌트를 렌더링하는 순간
useState(0)은 바로 호출되어 상태가 등록된다.


SSR 시점에서는 useState도 서버에서 한 번 실행된다

SSR(Server-Side Rendering)에서는 React가 서버에서 컴포넌트를 실행합니다.
이때 useState 초기값이 평가되어 HTML이 생성된다.

예를 들어

function Greeting() {
  const [name, setName] = useState("게스트");
  return <p>{name}님 안녕하세요</p>;
}

서버에서 이 컴포넌트를 렌더링하면
"게스트님 안녕하세요"라는 HTML이 만들어지고 브라우저로 전달된다.

이때 React는 useState("게스트")의 초기값을 서버 메모리 안에서만 기억하고,
브라우저에는 실제로 state 정보는 전송하지 않는다.
즉, HTML만 보냄.


클라이언트 Hydration 단계에서 useState가 다시 초기화된다

이제 브라우저가 HTML을 받아서 React를 실행할 때,
같은 컴포넌트가 다시 렌더링된다.

이 시점에서도 React는
useState("게스트")를 다시 실행하면서 초기 상태를 복원하려고 시도한다.
하지만 여기서 중요한 점

이 초기값은 서버에서 렌더링된 값과 반드시 동일해야 한다.

만약 서버와 클라이언트의 초기 상태가 다르면?

function Greeting() {
  const [name, setName] = useState(
    typeof window !== "undefined" ? localStorage.getItem("user") : "게스트"
  );
  return <p>{name}님 안녕하세요</p>;
}

서버에서는 "게스트"
클라이언트에서는 "나나"
→ Hydration 시점에 React는 DOM과 Virtual DOM이 다르다Hydration Mismatch Warning 을 띄운다.

이게 흔히 말하는 “Hydration-safe하지 않은 코드”이다.


그럼 안전하게 쓰려면 어떻게 해야 할까?

Hydration-safe하게 useState를 사용하는 기본 원칙은 👇

✅ 원칙 1. 초기값은 SSR과 CSR이 동일해야 한다.

const [theme, setTheme] = useState("light");

🚫 피해야 할 패턴

  • useState(window.innerWidth) — SSR에서는 window가 없으므로 오류
  • useState(localStorage.getItem("theme")) — SSR에서는 접근 불가

→ 이런 경우엔 useEffect를 써서 Hydration 이후에 값 갱신으로 옮겨야 함.

const [theme, setTheme] = useState("light");

useEffect(() => {
  const saved = localStorage.getItem("theme");
  if (saved) setTheme(saved);
}, []);

이렇게 하면 SSR 단계에서는 "light"로 렌더되고,
Hydration이 끝난 뒤에만 실제 localStorage 값을 반영하게 된다.
서버와 클라이언트의 초기 일관성이 유지되어 경고가 사라짐.


useEffect와의 비교 정리

구분실행 시점SSR에서 실행 여부주요 역할
useState렌더링 중✅ 실행됨 (초기값만 평가)상태 초기화
useEffect렌더링 완료 후 (Hydration 끝난 뒤)❌ 실행 안 됨브라우저에서 부수효과 처리 (fetch, DOM 조작 등)

결론

useState화면을 그릴 때 실행되고,
useEffect화면이 다 그려진 뒤 실행된다.
그래서 SSR 환경에서는 useState의 초기값이 서버·클라이언트 간 동일해야 한다.

profile
Frontend Developer

0개의 댓글