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