SSR이란 무엇인가요?
SSR(Server Side Rendering)은 웹 애플리케이션의 초기 HTML을 서버에서 렌더링하여 클라이언트에 전달하는 방식입니다. 이를 통해 사용자는 초기 페이지 로딩 시 빠르게 콘텐츠를 확인할 수 있으며, 검색 엔진 최적화(SEO)에도 유리합니다.
SSR의 동작 원리

- 클라이언트 요청: 사용자가 웹 페이지를 요청합니다.
- 서버 렌더링: 서버는 React와 같은 프레임워크를 사용하여 HTML을 생성합니다.
- HTML 전달: 생성된 HTML과 JavaScript 번들을 클라이언트에 전송합니다.
- Hydration: 클라이언트는 전달받은 HTML을 기반으로 React 컴포넌트를 활성화하여 동적 기능을 추가합니다.
이 과정에서 서버와 클라이언트 간의 렌더링 결과가 일치하지 않으면 Hydration Error가 발생할 수 있습니다.
Hydration Error의 원인과 해결 방법
1. 서버와 클라이언트의 렌더링 결과 불일치
서버에서 렌더링된 HTML과 클라이언트에서 React가 재사용하는 HTML이 다를 경우, React는 이를 일관성 오류로 간주하고 Hydration Error를 발생시킵니다.
예시: 날짜/시간, 랜덤 값 사용
// 잘못된 예시 (SSR에서 렌더링 시점의 값이 사용됨)
const currentTime = new Date().toLocaleTimeString();
- 문제: 서버와 클라이언트에서 new Date()의 결과가 다를 수 있습니다.
해결 방법:
// 클라이언트에서만 계산하도록 useEffect 사용
const [currentTime, setCurrentTime] = useState('');
useEffect(() => {
setCurrentTime(new Date().toLocaleTimeString());
}, []);
- 설명: useEffect를 사용하여 클라이언트에서만 값을 설정함으로써 서버와 클라이언트의 불일치를 방지합니다.
2. 브라우저 API(window, document 등) 사용
서버는 브라우저 API를 알지 못하므로, 이를 서버 사이드 코드에서 사용하면 Hydration Error가 발생할 수 있습니다.
예시: window 객체 사용
// 잘못된 예시 (SSR에서 window 사용)
const userAgent = window.navigator.userAgent;
- 문제: 서버에서는 window 객체를 사용할 수 없습니다.
해결 방법:
// 클라이언트에서만 window 사용
const [userAgent, setUserAgent] = useState('');
useEffect(() => {
setUserAgent(window.navigator.userAgent);
}, []);
- 설명: useEffect를 사용하여 클라이언트에서만 window 객체를 사용하도록 합니다.
3. 전역 상태 관리(Redux) 초기값 불일치
서버와 클라이언트에서 Redux 스토어의 초기값이 다르면 Hydration Error가 발생할 수 있습니다.
예시: localStorage 기반 초기값 설정
// 잘못된 예시 (SSR에서 localStorage 사용)
const initialState = {
user: {
name: localStorage.getItem('userName') || '',
},
};
- 문제: 서버에서는 localStorage를 사용할 수 없습니다.
해결 방법:
// 클라이언트에서만 localStorage 사용
const initialState = {
user: {
name: '',
},
};
const store = createStore(reducer, initialState);
if (typeof window !== 'undefined') {
const savedName = localStorage.getItem('userName');
if (savedName) {
store.dispatch(setUserName(savedName));
}
}
- 설명: 클라이언트에서만 localStorage를 사용하여 초기값을 설정합니다.
Hydration Error 예방을 위한 권장 사항
- 클라이언트 전용 코드 분리: useEffect를 사용하여 클라이언트에서만 실행되는 코드를 작성합니다.
- SSR Safe 초기값 설정: 서버에서 사용할 수 있는 기본값을 설정하여 초기 렌더링 시 불일치를 방지합니다.
- 동적 임포트 활용: next/dynamic을 사용하여 클라이언트 전용 컴포넌트를 동적으로 로드합니다.
import dynamic from 'next/dynamic';
const ClientOnlyComponent = dynamic(() => import('./ClientOnlyComponent'), {
ssr: false,
});
- 서버 환경 설정: 서버에서 사용하는 라이브러리의 locale이나 timezone을 명시적으로 설정하여 서버와 클라이언트 간의 일관성을 유지합니다.
결론
Hydration Error는 SSR 환경에서 서버와 클라이언트 간의 불일치로 인해 발생하는 일반적인 문제입니다. 이를 예방하기 위해서는 클라이언트 전용 코드와 SSR 전용 코드를 명확히 구분하고, 초기값 설정에 주의하며, 동적 임포트를 활용하는 등의 방법을 적용해야 합니다. 이러한 접근 방식을 통해 안정적이고 일관성 있는 웹 애플리케이션을 개발할 수 있습니다.
'NextJS' 카테고리의 다른 글
| [NextAuth] 비밀번호 변경 및 프론트엔드에서 비밀번호 변경 요청 보내기 - 10 (0) | 2025.11.20 |
|---|---|
| [NextJS] Module not found: Can't resolve 'net', Module not found: Can't resolve tls (0) | 2025.10.29 |
| NextJS 로딩 상태 처리 (0) | 2025.10.20 |
| [NextJS] 서버 컴포넌트에서 DB 직접 접근 (0) | 2025.10.19 |
| [NextJS] 서버 컴포넌트에서 데이터 직접 가져오기 (Server-Side Fetching) (0) | 2025.10.18 |