2019年03月18日

ReactでSSR(ルーティング)

前回(ReactでSSR)は単純なSSRをやったので今回はルーティングを含めた対応をやっていきます。

まずはreact-router-domのインストールを行います。

npm install react-router-dom


まずはReactのみでルーティング



react-router-domのBrowserRouterを読み込みAppコンポーネントを包みます。ちなみにサーバーサイドではBrowserRouterではなくStaticRouterという機能を利用するのでサーバーサイドに影響を受けないレイヤーで記述しておく必要があります。
また、ReactDOM.renderではなくReactDOM.hydrateを利用しています。ReactDOM.hydrateを利用することでSSRされたDOMをベースにReactがアプリケーションを構築してくれるようになります。

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from "react-router-dom";
import { App } from './App';

ReactDOM.hydrate(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('app')
);


App.jsではHomeコンポーネントとAboutコンポーネントを読み込みルーティングに準じて表示を切り替えています。

import React from 'react';
import { Home } from './Home';
import { About } from './About';
import { Route, Link } from "react-router-dom";

export const App = () => (<div>
<Link to="/">Home</Link>
<Link to="/about/">About</Link>
<Route exact path="/" component={Home} />
<Route path="/about/" component={About} />
</div>)


Home.jsとAbout.jsでは適当なコンポーネントを定義しています。

import React from 'react';
export const Home = () => <h1>React Home</h1>


import React from 'react';
export const About = () => <h1>React About</h1>



クライントサイドはこれでちゃんと動作しますが、http://localhost:3000/aboutでリロードをするとファイルがないと怒られてしまいます。

server.jsは次のように変更します。StaticRouterにlocationを与えてReactDOMServer.renderToString()を行うことでそのURLで描画されるべきHTMLが表示されるのでそれをHTMLに挿入しておきます。

import express from 'express'
import React from 'react'
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import fs from 'fs'
import path from 'path'
import { App } from './src/App.js'

const app = express()

app.use(express.static('./dist'));

app.get('/*', (req, res) => {
const context = {};
const app = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);

fs.readFile(path.resolve('./dist/index.html'), 'utf8', (err, data) => {
return res.send(
data.replace(
'<div id="app"></div>',
`<div id="app">${app}</div>`
)
)
})
})

app.listen(3000)


これで変更は終了です。次はReact Helmetとの連携です。

参考:Using React Router 4 with Server-Side Rendering ← Alligator.io
posted by ねこまんま at 15:28 | React | 更新情報をチェックする