サーバーサイドレンダリング
ReactのVirtualDOMから、DOMではなくHTMLを書き出す つまりクライアントではなくサーバーでHTMLをレンダリングする
ふつうの静的ページとして配信する
良い所
react.jsを読み込ませるよりも帯域を使わない
ケータイの回線だと最初に500kbダウンロードするのはつらい
JSXからStringに吐き出す方法
react-dom/serverにJSXをStringにする関数がある
これが
code:render-jsx.js
import {renderToStaticMarkup, renderToString} from "react-dom/server";
import React, {createElement} from "react";
const elm = <div className="test">かずすけ</div>
console.log(renderToString(elm));
console.log(renderToStaticMarkup(elm));
こうなる
code:output.html
<div class="test" data-reactroot="" data-reactid="1" data-react-checksum="408212768">かずすけ</div>
<div class="test">かずすけ</div>
renderToStringはreact用のdata-reactid等が付いたHTML
renderToStaticMarkupはプレーンなHTMLが出る
コンポーネントを書き出す場合
createElement関数をかますとpropsを渡せる
code:render-component.js
const MyComponent = ({message, className}) => {
return (
<div className={className}>{message}</div>
);
}
console.log(renderToStaticMarkup(createElement(MyComponent, {message: "ざんまい", className: "肉"})));
code:output2.html
<div class="肉">ざんまい</div>
Browserifyでjs以外をtransformして埋め込んでるような部分は自分で書かなければならない なのでStylify使わず普通にlinkタグでcss埋め込んだほうがいい 2行で使えるようになる
円環の理のstateからviewを表示する一部分だけを切り出せるようになっていればいい
ダメな例
viewが他のviewを参照している
viewの中からajaxして表示を作ってる
code:client/app.js
<App store={store} />
埋め込まれたstoreの持つstateだけで表示が全て構築されるように
そしてstoreはAppから順に下のコンポーネントへ渡っていく
もしくは必要な値だけpropsで渡っていく
初期stateだけでcreateStoreしてAppに渡す
code:js
export default function IndexStaticHTML({state}){
const store = createStore((state) => state, initState);
return (
<html>
<head><title>{state.title}</title></head>
<body>
<App store={store} />
</body>
</html>
)
}
stateそのまま返すだけのreducerと、initStateだけ
middlewareは使わない
renderToStaticMarkupすればonClick内のイベントは潰されるので普通のaタグになる
クライアントレンダリングの場合はAjax+pushState
サーバーレンダリング時は普通のリンクという風にできる
code:js
<a href="/shokai/hello" onClick={() => e.preventDefault(); action.route({wiki: "shokai", title: "hello"})} />
DOMが必要な処理を書かない
もし書くならhas-dom等で環境チェックしてからやる
MongoのDocumentをそのままstateとして渡さない
サーバーで
code:server.js
const page = Pages.findOne({title, wiki});
ctx.render("index-static", {state: {page}});
するとReact側でstateの中にmongo documentがそのまま渡る
React内でpropリレーしていくと、末端でなぜかstateが_docキーの中に入ってしまった
documentをふつうのobjectに変換してから渡したほうがいい
code:server.js
ctx.render("index-static", {state: {page: page.toObject()}});
ツール
% npm install has-dom
DOMがある環境かどうか判定、true/falseを返すだけのライブラリ
code:js
import hasDom from "has-dom";
var user = hasDom() ? window.user : null;
% npm i get-doc
documentがあれば返す、無ければnull
code:js
import doc = "get-doc";
doc.getElementById("app");