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