React는 주로 클라이언트 사이드 렌더링(Client-Side Rendering, CSR)을 기반으로 동작하지만, SEO(검색 엔진 최적화) 및 초기 로딩 속도를 개선해야 하는 경우 서버 사이드 렌더링(Server-Side Rendering, SSR)을 활용할 수 있습니다. 이 글에서는 React에서 서버 사이드 렌더링을 구현하는 방법과 관련 기술을 상세히 살펴보겠습니다.
1. 서버 사이드 렌더링이란?
서버 사이드 렌더링(SSR)은 React 애플리케이션을 서버에서 렌더링하여 완전한 HTML을 클라이언트에 전달하는 방식입니다. 이 방식은 사용자가 브라우저에서 초기 페이지 로딩 시 바로 콘텐츠를 확인할 수 있게 하며, 검색 엔진이 콘텐츠를 더 쉽게 크롤링할 수 있도록 돕습니다.
SSR의 주요 장점
- SEO 최적화: HTML에 콘텐츠가 포함되어 있어 검색 엔진이 페이지를 크롤링하기 쉽습니다.
- 빠른 초기 로딩: 사용자에게 완성된 HTML이 전달되므로 초기 화면이 빠르게 표시됩니다.
- 소셜 미디어 미리보기 개선: Open Graph 태그 등의 메타 정보가 포함된 HTML을 제공할 수 있어 공유 시 미리보기가 잘 작동합니다.
SSR의 단점
- 서버 부하 증가: 클라이언트에서 처리하던 렌더링 작업이 서버에서 처리되므로 서버 부하가 늘어납니다.
- 구현 복잡성 증가: 데이터 패칭, 상태 관리 등이 추가로 요구됩니다.
2. React에서 SSR 구현을 위한 준비
React에서 SSR을 구현하려면 아래 기술 스택 및 도구를 사용합니다:
- Node.js: 서버 환경 제공
- Express.js: 서버 구성 및 라우팅
- ReactDOMServer: 서버에서 React 컴포넌트를 렌더링하기 위한 메서드 제공
- Webpack: 번들링 도구 (선택 사항)
필수 패키지 설치
SSR을 구현하기 위해 필요한 패키지를 설치합니다:
npm install react react-dom express react-dom/server
3. SSR 구현 단계
(1) Express 서버 구성
Express를 사용해 기본적인 서버를 설정합니다. 서버는 클라이언트 요청에 따라 React 애플리케이션을 렌더링하고 HTML을 반환합니다.
const express = require('express');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const App = require('./App');
const app = express();
const PORT = 3000;
// 정적 파일 서빙
app.use(express.static('public'));
// React 애플리케이션 렌더링
app.get('*', (req, res) => {
const appHTML = ReactDOMServer.renderToString(React.createElement(App));
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React SSR Example</title>
</head>
<body>
<div id="root">${appHTML}</div>
<script src="/bundle.js"></script>
</body>
</html>
`;
res.send(html);
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
(2) React 애플리케이션 작성
기본 React 컴포넌트를 작성합니다. 이 컴포넌트는 서버와 클라이언트 모두에서 렌더링될 수 있습니다.
// App.js
const React = require('react');
function App() {
return (
<div>
<h1>React 서버 사이드 렌더링</h1>
<p>이 페이지는 서버에서 렌더링되었습니다.</p>
</div>
);
}
module.exports = App;
(3) Webpack을 통한 번들링 (선택 사항)
React 애플리케이션을 브라우저에서 실행하기 위해 Webpack을 사용해 클라이언트용 번들을 생성합니다.
Webpack 설정 파일 작성
// webpack.config.js
const path = require('path');
module.exports = {
entry: './index.js',
output: {
path: path.resolve(__dirname, 'public'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: 'babel-loader',
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
},
};
Babel 설정 파일 작성
React 코드를 컴파일하기 위해 Babel 설정을 추가합니다:
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
4. 서버와 클라이언트 통합
서버에서 렌더링된 HTML은 클라이언트에서 React 애플리케이션과 결합되어야 합니다. 이를 위해 React의 hydrate 메서드를 사용합니다.
// index.js (클라이언트 엔트리 포인트)
const React = require('react');
const ReactDOM = require('react-dom');
const App = require('./App');
ReactDOM.hydrate(
React.createElement(App),
document.getElementById('root')
);
hydrate는 서버에서 렌더링된 HTML과 클라이언트의 React 상태를 연결합니다.
5. 데이터 패칭과 SSR
SSR에서 데이터 패칭은 중요한 고려 사항입니다. 데이터가 준비되기 전에 HTML을 렌더링하면 빈 콘텐츠가 전달될 수 있습니다. 이를 방지하려면 서버에서 데이터를 미리 가져오고, 렌더링 시 해당 데이터를 React 컴포넌트에 전달해야 합니다.
데이터 패칭 구현 예제
// 서버에서 데이터 가져오기
app.get('*', async (req, res) => {
const data = await fetchData(); // 서버에서 데이터 요청
const appHTML = ReactDOMServer.renderToString(
React.createElement(App, { data })
);
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React SSR with Data</title>
</head>
<body>
<div id="root">${appHTML}</div>
<script>window.__INITIAL_DATA__ = ${JSON.stringify(data)}</script>
<script src="/bundle.js"></script>
</body>
</html>
`;
res.send(html);
});
클라이언트에서 초기 데이터를 받아 사용하는 코드는 다음과 같습니다:
const data = window.__INITIAL_DATA__;
ReactDOM.hydrate(
React.createElement(App, { data }),
document.getElementById('root')
);
6. 결론
React에서 서버 사이드 렌더링을 구현하면 SEO와 초기 로딩 속도를 대폭 개선할 수 있습니다. 위에서 설명한 단계를 따라 기본적인 SSR 구조를 설정하고, 데이터 패칭 등 고급 기능을 추가하여 더욱 효율적인 애플리케이션을 구축해보세요.
'React' 카테고리의 다른 글
React에서 Babel 설정하기 (0) | 2024.12.16 |
---|---|
React에서 Webpack 설정하기 (0) | 2024.12.16 |
React에서 Suspense와 Concurrent Mode 이해하기 (0) | 2024.12.16 |
React에서 React.StrictMode 사용법 (1) | 2024.12.16 |
React에서 REST API와 GraphQL 비교하기 (0) | 2024.12.13 |