【基礎】ReactでServer Side Rendering

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

# Express + ReactでSSR
参考：[React での ServerSideRendering 入門](https://qiita.com/euxn23/items/10d051c62e7b2160f4fc)

## 準備
```bash
npm install express-generator -g
express myapp
cd myapp
npm install
npm install react react-dom node-jsx

npm start
```

## サンプルコンポーネント
ただのReactコンポーネント。

```jsx: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文字にする。

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

```js: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に、変化と、その表示をさせてみよう。

```jsx: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](https://qiita-image-store.s3.amazonaws.com/0/24484/e20524e8-0b4b-1124-f1c6-7f7fe79d5f59.gif)

# ブラウザでReactを動かす
あれじゃあどうやって仮想DOM使うんだ・・？

と調べると・・。
参考：[hydrateでSSR後にブラウザでReactを動かす](https://tokita.club/posts/5)

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

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

## というわけでwebpack準備
```bash
npm install -D \
webpack webpack-cli \
babel-cli babel-preset-env babel-preset-react babel-loader
```

※"webpack": "^4.10.1"

```js: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
に変えてあげればいいみたい。

```js: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にコンテナを用意。

```js:app.js
・・・

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

・・・
```

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

動いた動いた。
![addReact.gif](https://qiita-image-store.s3.amazonaws.com/0/24484/684498c1-7527-6fa4-9c7a-1401507d9f6c.gif)