31
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【基礎】ReactでServer Side Rendering

Posted at

概要

SSRの勉強をしたくて、Qiitaを漁ったら、
思いの外、他の方の記事がわかりづらかった(私の能力が低いだけです

Express + ReactでSSR

参考:React での ServerSideRendering 入門

準備

npm install express-generator -g
express myapp
cd myapp
npm install
npm install react react-dom node-jsx

npm start

サンプルコンポーネント

ただのReactコンポーネント。

components/sample.js
const React = require('react');

module.exports = class Sample extends React.Component {
    render(){
        return (
            <div>
                hoge
            </div>
        );
    };
};

Viewをブラウザに返す

node-jsxを入れておくと、requireでJSXを解釈してくれるので
入れておいたほうがいい。

Reactコンポーネントを読み込んで、
ReactDomServer.renderToStringでHTML文字にする。

あとはそれをブラウザに渡す。

app.js
・・・

require('node-jsx').install({harmony: true});

const React = require('react');
const ReactDomServer = require('react-dom/server');

var Sample = require('./components/sample');

const createHtml = component => (`
<html>
    ${component}
</html>
`);

・・・

//app.use('/', index);
app.use('/', (req, res, next) => {
    const sampleComp = ReactDomServer.renderToString(React.createElement(Sample));
    const view = createHtml(sampleComp);
    res.status(200).send(view);
});

・・・

今表示されているものは静的なHTML

のはず。

hogeを表示させるだけだとよくわからないので、
Componentのstateに、変化と、その表示をさせてみよう。

components/sample.js
const React = require('react');

module.exports = class Sample extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count: 0
        };

        this.click = this.click.bind(this);
    }

    render(){
        return (
            <div>
                <input type="button" onClick={this.click} value="CountUP"></input>
                <div>{this.state.count}</div>
            </div>
        );
    };

    click() {
        this.setState({
            count: this.state.count + 1
        });
    }
};

うん、ボタン押しても動かない。
noReact.gif

ブラウザでReactを動かす

あれじゃあどうやって仮想DOM使うんだ・・?

と調べると・・。
参考:hydrateでSSR後にブラウザでReactを動かす

マジカヨ。
結局、ブラウザ用にファイル用意するのね・・。

わしゃてっきり、webpackから解放されるものかと・・。

というわけでwebpack準備

npm install -D \
webpack webpack-cli \
babel-cli babel-preset-env babel-preset-react babel-loader

※"webpack": "^4.10.1"

webpack.config.js
const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'public'),
        filename: 'index.js'
    },
    module: {
        rules: [
            {
                test: /\.(js)$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            'babel-preset-react',
                            'babel-preset-env'
                        ]
                    }
                }
            }
        ]
    }
};

肝は、express-generatorで作成したアプリなので、
デフォルトでpublicディレクトリが静的なファイルを置く場所と決まっていることだ。

なので、bundleファイルもそこに出力されるようにする。

表示の置換

参考を見る限り、
静的HTMLを、ReactのViewに後から置き換わるようにすれば良いみたい。

これは、ブラウザでReactを書いている人には馴染み深い
ReactDOM.render
とほぼ一緒だ。

renderではなく置換(という言葉であっているのか・・?)させる、
ReactDOM.hydrate
に変えてあげればいいみたい。

src/index.js(ブラウザ側Reactのエントリーポイント)
const React = require('react');
const ReactDOM = require('react-dom');
var Sample = require('./../components/sample');

ReactDOM.hydrate(
    <Sample />,
    document.getElementById('root')
);

bundleファイルを読み込みと、
DOMにレンダリング(置換)しないといけないので、最親のHTMLにコンテナを用意。

app.js
・・・

const createHtml = component => (`
<html>
    <div id="root">${component}</div>
    <script src="index.js"></script>
</html>
`);

・・・
bundleファイル作って、サーバ起動して・・
./node_modules/.bin/webpack
npm run start

動いた動いた。
addReact.gif

31
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?