『入門React: コンポーネントベースのWebフロントエンド開発』学習メモ
Part 1 基礎
Ch01 Introduction
- 背景
- React: XHPというPHPのframeworkのJavaScriptへの移植
Ch02 JSX
- Separation of concernsのために,Componentを使う ←→ templateと表示logicといった分離
- Component: Markupとそれを生成するcodeが強く結びついたもの.Reactの中心的な概念.
- What's JSX
- JSX: JavaScript XML
- ReactのComponent内でMarkup言語を記述するためのXML風のsyntax
- 特徴
- JSXはsyntax拡張.(あとでJavaScriptの関数呼び出しに変換される)
- JSXはruntime libraryが不要
- JSXはただの関数呼び出し
- JSXのmerit
- 既知の構文
- 意味的な分かりやすさ
- JavaScriptのcodeをよりsemanticで意味のあるMarkup言語で記述できる
- Componentの構造と情報のflowはHTML風なsyntaxで宣言的に記述
- applicationで定義されたcustom Componentをタグ名として使用〇
- 構造の可視化
- 抽象化
- projectの進展に伴うcodeの変更を減らす
- Separation of concerns
- Component内のMarkupとBusiness Logicを分離
- Component合成
- custom Componentの定義
- dynamic value
- child node
- this.props.children: start-end tag内の全子nodes
- JSXとHTMLの違い
- JSXなしでReactを使用したい場合
- ReactElementの作成
- 簡略化
- 参考文献
Ch03 Componentのlifecycle
- Component: state machine → inputに対して常に同じoutput
- Component作成時に呼ばれるmethod
- Componentのinstance作成~初回描画
- Componentを利用可能にするための設定
- getDefaultProps
- Componentにつき1回のみ
- 非scalar値は共有
- getInitialState
- instance作成事
- ここからthis.propsが利用できる
- componentWillMount
- 初回の描画前
- renderの前にComponentのstateを変える最後の機会
- render
- Virtual DOM(Componentのoutput)を作成
- ReactのComponent中で唯一省略できないlifecycle method
- rules
- componentDidMount
- Componentのinstance作成~初回描画
- Component作成後に呼ばれるmethod
- componentWillReceiveProps
- 親Componentがpropを変更したとき
- shouldComponentUpdate
- optimezeのためにある
- develop時には使わない.tuningで使う.
- PureRenderMixinでperformance tuneも〇
- componentWillUpdate
- state, propsの更新は×
- componentDidUpdate
- 変更されたDOMのreferenceへのaccess
- componentWillReceiveProps
- Component破棄時に呼ばれるmethod
- 不要になったらReact DOMから切り離してdelete
- componentWillUnMount
- deleteの直前
- 後処理できる
- timer, event listenerなど
- anti pattern: 加工された値をstateに保存する
- a single source of truthの原則 @React
- → 単一のinformationのcopyが可能になる
- e.g.
- initialValueはOK
- a single source of truthの原則 @React
- まとめ
- lifecycle method: applicationがComponentのeventにeffectiveに反応できるようdesign
- 各Component: state machine.一貫して安定した予測可能なmarkupをoutput
Ch04 data flow
- 基本は親から子への一方通行
- Component: 親からのpropを描画
- propの変更 → propを参照する全Componentが再描画
- 内部state: Componentの内部でのみ変更可能
- Component: propsとstateをinput, Virtual DOMをoutputする一種のfunction
- props
- props: Componentに渡される任意のdata
- setProps: 子Componentに対して呼ぶか,Component treeの外側で呼ぶのみ
- Componentは自身のpropsを変えない
- JSXでのpropsの指定
- ...: 後に続くObjectをその場に展開
- event handlerの格納も〇
- propTypes: propsとして渡された値をvalidate
- Componentの仕様が明確になるため,使用推奨
- getDefaultProps
- React.createClass時にキャッシュ
- state
- Componentの内部でのみ使用
- 要素の表示内容の決定に使う
- getInitialStateっでinitialize
- setState
- 必ずrender()を伴う
- directにthis.stateの変更は絶対×
- なるべく一部のComponentのみ
- 複雑になるため
- stateとpropsの使い分け
- stateはComponentの機能にdirectに必要な単純なdataのみに〇
- propsの値をstateにcopy×
- まとめ
- prop経由でCompにdataを渡し,tree全体に伝播
- propsはimmutableとして扱う(Component内)
- 子Componentとのやりとりのために,event handlerをpropsに指定
- 表示内容を決定するためのsimpleなdataのみstateに保存可能
- this.setStateを必ず使う
Ch05 event_processing
- UIの半分は表示,残りの半分はuserのinputに反応すること
- JavaScriptで,userのinput eventに応じたevent_handlerを記述する
- Reactでのevent_processing
- まずevent_handlerを登録
- handlerが呼び出されたときにcomponentのstateを変更する処理を記述
- render method内でstateを参照しさえすれば,変更は自動的に描画に反映される
- 追加の情報は,event_handlerに引数として渡されるevent objectが追加の情報を含んでいるので,それをもとにstateを適切に更新できる
- techniqueとReactの高性能なRenderingの仕組みにより,容易にuser inputに反応してUIを更新できる
- event_handlerの登録
- onClick
- eventとstate
- たいていはsetStateで既存のObjectにマージする
- Object変更時は必ずsetState/replaceState
- event_object
- event.target.valueからformのinputを取得
- 特にonChangeでよく使われる
- event.target.valueからformのinputを取得
- まとめ
- Reactでuser inputをUIに反映させる手順
- React componentにevent_handlerを登録する
- event_handler内でcomponentのstateを変更する.stateを変更するとcomponentは再描画される.
- componentのrender method内でthis.stateを参照するように変更する
- Reactでuser inputをUIに反映させる手順
Ch06 componentの合成
- HTMLではpageは要素から構成されるが,Reactではcomponentから構成される
- ReactのcomponentはHTMLの要素にJavaScriptの表現力が追加されたもの
- component: propsとstateをinputとして受け取り,HTMLを出力として返す一種の関数のようなもの
- 各componentはapplication内のデータの一部を表示するために設計されている → React componentはHTMLの拡張といえる
- HTMLの拡張
- lifetimeを通じて,React_componentは振る舞いをcontrolできる
- React.createClass
- 継承より合成
- 小さくて単純なcomponentを組み合わせて,より大きくて複雑なapplicationを構築する
- 合成の例
- has aで表現できる
- 汎用的なinput要素から初めて,radiobuttonにcustomizeし,多肢選択の機能を提供する例
- original form controlのcomponentの作成
- 親子間の関係
- 親child_componentでの通信の最も簡単な方法: propsを使う.親がcallback functionをpropsとして渡して,子がそれを呼び出す
- child_componentの変更に対する振る舞いを定義
- 親child_componentでの通信の最も簡単な方法: propsを使う.親がcallback functionをpropsとして渡して,子がそれを呼び出す
- まとめ
- Reactにおいて合成のpatternを使用する手法
- HTMLの要素や自信のcustom componentをwrapして,必要に応じてそれらの機能をcustomizeすることで,componentを作成する
- 汎用的なcomponentは,合成のたびに特化され意味を持ったものになる
- Mixin: 合成以外の方法 → 次章
- Reactにおいて合成のpatternを使用する手法
Ch07 Mixin
- Mixin: 複数のcomponent間で共有可能なmethodを定義できる
- Mixinとは
- Mixinを使ったTimer componentの実装
- componentにmixinsというpropertyを定義する
- 制限
- 複数のタイマーは持てない
- Timer eventのhandler methodの名前はonTickに固定
- タイマーを止めるには内部の__interval propertyにアクセスする必要がある
- → コードは増えるが修正できる
- 適用例
- eventを監視してstateを更新するMixin(e.g. FluxのStore Mixin)
- XHRのuploadを行いprogressをstateに反映するMixin
- child_componentをの末尾に表示するためのlayer Mixin(e.g. modal dialog)
- まとめ
- Mixin: codeの重複を避けるために有効な手段
- componentは自身に固有の責務に集中できる
- 強力な抽象化の手段を提供
- ある特別なふるまいや役割をcomponentと切り離して記述できるので,codeはより理解しやすいものになる
- Mixinとして定義できないか常に検討する
- Mixin: codeの重複を避けるために有効な手段
Part 2 応用
Ch08 DOM操作
- 通常はReactの提供するAPIだけでUIを構築できるので,実際のDOMに直接アクセスすることはほとんどない
- componentを合成することで,複雑なUIをまとまった全体としてuserに提示できる
- Reactとともに使用することを想定していないthird partyのlibraryを導入する場合や,Reactで非supportのDOM操作を行いたいときがは,DOMへのアクセスが必要になる
- componentのlifecycleの特定の局面でしか利用できないという制限あり
- DOM_nodeへのaccess
- まずそのnodeを表現するcomponentにアクセス
- componentにref属性を設定して実現する
- ref属性はcomponentのすべての子nodeの中でuniqueである必要あり
- ほかの子nodeのref属性と重複は×
- ref属性はcomponentのすべての子nodeの中でuniqueである必要あり
- → componentDidMountの中で,React.findDOMNode()を使って実際のDOM_nodeにアクセス
- event_handler中でも〇
- componentにref属性を設定して実現する
- どうしても必要な場合以外は使わない
- Reactが内部で行う最適化の妨げになるうえ,applicationが複雑化する要因になる
- まずそのnodeを表現するcomponentにアクセス
- React friendlyでないlibraryの使用例
- オートコンプリートlibraryの例
- 行儀の悪いlibrary
- 自身がアタッチされた要素の内容を,カスタムイベント経由で変更してしまうpluginの例
- 親の要素まで変更する場合は対応できないので,Reactとの併用はできない
- Reactを守るために,pluginの使用するDOM_nodeを完全にcontrolする必要がある
- componentDidMountの中で独自に要素を作成し,renderで作成された要素の子nodeとして追加する
- 不要になった際は自分自身で削除が必要 @componentWillUnMount
- pluginのdocumentをみて,ほかに必要な手順がないか確認する
- global event_listenerやtimerやAJAX requestなど
- pluginのdocumentをみて,ほかに必要な手順がないか確認する
- Reactに管理されていないdivの描画の更新
- 確実: componentを疑似的にpageから削除して追加する
- 簡潔でperformance〇: pluginの更新用のAPIを呼び出す
- ごく単純なpluginの場合は,同じ機能を提供するReact componentを作ってしまった方が早いこともある
- 自身がアタッチされた要素の内容を,カスタムイベント経由で変更してしまうpluginの例
- まとめ
- Reactが提供するAPIだけでは不十分で,どうしても実際のDOMにアクセスしなければいけない場合がある
- ref属性を設定して,特定のcomponentにアクセスし,そのcomponentの実際のDOM_nodeへの参照をReact.findDOMNode()経由で取得する
- componentDidMountが呼び出されてからでないとアクセスできない
- → ReactがサポートしていないDOM操作や,Reactとともに使われることを考慮されていないthird partyのlibraryの使用が可能になる
- ref属性を設定して,特定のcomponentにアクセスし,そのcomponentの実際のDOM_nodeへの参照をReact.findDOMNode()経由で取得する
- Reactが提供するAPIだけでは不十分で,どうしても実際のDOMにアクセスしなければいけない場合がある
Ch09 form
- single_page_applicationでは,formを正しく扱うのは至難
- user inputにより扱うべき状態が一気に増えるため
- formの複雑な状態の管理のために,Reactを使える
- React_componentの主要な側面
- 動作が予測可能であること
- testの容易さ
- ↑ 同じ内容のpropsとstateで描画を行った場合,常に同じ描画結果を出力するというReact_componentの特徴のため
- Reactのformのcomponentには,管理された/されていないcomponentの2種類がある
- 複雑なformを扱う場合などは,DOMにアクセスが必要になる
- 管理されていないcomponent
- 複雑なformに向いている
- 直接DOM_nodeにアクセス
- ある意味アンチパターン
- formはほかのReact_componentと異なる動作
- 値は要素が管理し,formは管理しない
- DOM_nodeに直接アクセスが必要
- ref: React独自の特性
- validationや入力制御を行う必要がないformに向いている
- 管理されたcomponent
- 通常のReact_component patternを踏襲する
- valueをcomponentのstateとして保持することで,React_component自身がform stateを管理する
- formを完全にcontrolしたい場合
- dataflowが明確になる
- codeは増えるが,データが入力されるたびにstateが変化するため,dataflowを完全にcontrol〇
- data input中にほかのcomponentの値の参照も可能
- form event
- event: form stateのcontrolに欠かせない
- HTMLで発生するすべてのeventに対応
- target property経由で,発生元のDOM_nodeにアクセスできる
- targetを参照することで,管理されたcomponentにおいて,user inputにアクセスできる
- label
- radiobuttonやcheckboxの意味をuserに伝える
- htmlFor @JSXがHTMLのfor属性
- classをclassNameと扱うのと同じ理由(予約語)
- textareaとselect
- 統一性と使いやすさのために,original HTMLの仕様から変更されている
- select
- 複数選択が有効だと,child_componentのoption要素のselected propertyのみ変更される
- checkboxとradiobutton
- checked属性をcontrolする
- form要素のname属性
- 基本はあまり重要ではない
- 欠かせない場面
- formをseriarizeするthird_partyのpluginをReactとともに使うとき
- submit eventを横取りせずにbrowserに処理を任せるとき
- browserのauto complete機能はuserのmail addressなどを提示するためにname attributeを使う
- 管理されていないradiobuttonの場合,同じname属性を持つ要素同士は同時に1つしか選べないのがdefault動作
- 管理されたradiobuttonでは,event_handlerで処理を行い同様の動作を実現
- 複数のform要素とchange event_handler
- change event_handlerの再利用の方法・例
- bind経由でevent_handlerに追加の引数を渡す
- event_handler内でDOM_nodeのname attributeを参照する
- React.addons.LinkedStateMixinも異なる方法で解決する
- linkState method
- form input valueを親componentのstateとして保持する場合は,とてもsimpleになる
- dataflowを細かく制御したい場合は,かえって複雑になる
- change event_handlerの再利用の方法・例
- custom form component
- checkbox, radiobuttonなどの複雑なcomponentのinterfaceを改善するためにも使われる
- ほかのform componentとinterfaceを合わせる
- 可読性のため
- focus
- formへのfocus設定: userが次に取るべき行動を明確に伝える良い方法
- 使いやすさも〇
- autoFocus attribute
- focus()
- formへのfocus設定: userが次に取るべき行動を明確に伝える良い方法
- usability
- 要求を明確に伝える
- label: formの要素が何を期待しているのか伝えるRole
- radiobutton, checkbox
- placeholderよりも,labelやpopupが〇
- label: formの要素が何を期待しているのか伝えるRole
- inputに即座に反応する
- validation
- 最善のtiming: input要素のblur event発生時
- 処理中であることを示す
- transition, animation
- validation
- performance
- transition, network delayなどによる動作の遅延について
- 速度は相対的かつ体感的
- 速いように見せることがimportant
- predictable
- platformのdefault 動作に準拠するか,userの操作をまったく異なったものにする
- 一貫性
- platformの標準動作に準拠
- accessibility
- 試しに単一のinput deviceでapplicationを操作してみる
- Accessible Rich Internet Applications(ARIA)
- Accessibility Developer Tools
- input項目数の削減
- usability〇
- 実際の項目数よりも,userがどう感じるか
- input項目を複数の小さいformに分割
- autocomplete
- autoFocus
- 要求を明確に伝える
- まとめ
- Reactでは,form state managementはDOMではなくcomponentで行う
- form要素の動作を完全に制御
- application固有の複雑なcomponentを作成できる
- formはapplication内で最も複雑な操作を必要とする
- form design時にはusabilityに配慮が重要
- Reactでは,form state managementはDOMではなくcomponentで行う
Ch10 animation
- applicationを洗練されたものにするための方法
- animation: user_experienceを滑らかで自然なものにする効果がある
- CSSTransitionGroupというアドオンをCSS3とともに使用する → 簡単にanimationを追加
- 初期はimperative(命令的)だった
- DOM要素に直接accessして座標値などのstyleを絶え間なく更新
- → ReactではCSS animationを利用した,よりdeclarativeな手法
- CSSTransitionGroup
- CSSを使わずにJavaScriptのtimerを使ってanimationを行うこともできる
- CSSを用いたanimation
- CSSTransitionGroup
- transitionの適用対象となるcomponentのgroupを表し,componentが追加/削除されるたびに自動的にCSS_styleを切り替えてanimationを実現する
- transitionのclassごとにstyleを記述する
- componentのtransitionName attributeの値に基づいて,4つのCSS class名が作成される
- -enter, -enter-active, -leave, -leave-active
- componentのtransitionName attributeの値に基づいて,4つのCSS class名が作成される
- transitionのlifecycle
- -enter classがchild_componentが追加されたときに適用され,すぐに(次のanimation frameで) -enter-active classが適用される
- transitionの開始時と終了時のstyleおよびそれらの間をどのように遷移するか定義できる
- transitionEnter={false}とすると無効にできる(transitionLeaveも同じ)
- 上位のcomponentからprop経由で設定もok
- -enter classがchild_componentが追加されたときに適用され,すぐに(次のanimation frameで) -enter-active classが適用される
- よくある過ち
- leaveのanimationが完了するまでchild_componentは削除されない
- child_componentのkey attributeはtransition group内でunique要
- CSSTransitionGroup
- timerを用いたanimation
- 古いbrowserに対応したり,ScrollのanimationやCanvas描画などを扱いたい場合
- CSS3のanimationよりperformance ×
- componentのstateが定期的に更新される
- stateはanimationのtimelineの中での現在位置を保持する
- render method中でこのstateの値を参照することで,applicationは適切なanimationのframeを描画できる
- 頻繁な再描画を行うので,timerのAPIとして一般的に効率的とされているrequestAnimationFrameを使う
- 代替: 効率で劣るsetTimeoutを使うしかない
- requestAnimationFrameを使ったanimation
- position: absolute
- 要素のstyleのleftとtopの値を時間の経過とともに更新する
- componentWillUpdate handler内で呼び出す例
- position: absolute
- setTimeoutを使ったanimation
- これらのときはsetTimeout
- requestAnimationFrameは少ないoverheadで滑らかなanimationの効果が得られるが,古いbrowserでは非support
- 絶え間なく呼び出されるのが煩わしいときもある
- React Tween State
- Open Source Library
- 汎用的なanimationのAPIを提供
- これらのときはsetTimeout
- まとめ
- Reactを使った以下のanimationを見た
- CSSTransitionGroup addon
- requestAnimationFrame
- setTimeout
- Reactを使った以下のanimationを見た
Ch11 performance_tuning
- Reactの差分描画のalgorithmは優れているので,UI全体を入れ替えたとしても実際のDOMの描画は最小限に抑えられる
- 深くnestしたcomponentなど,delicate tuneが必要な場面では,virtual_DOMの不要な入れ替えを避けることでperformance改善〇
- React componentの簡単な設定により,applicationのperformanceを改善する方法を見る
- shouldComponentUpdate
- shouldComponentUpdateで,Reactにcomponentのlifecycle methodを呼び出す必要があるか教える
- falseならrender methodを呼び出さず,描画済みのvirtual_DOM objectをそのまま使う
- defaultはtrue
- 初回描画時は呼び出されない
- 新しいpropsとstateを受け取るので,それをもとに決定できる
- componentがpure(同一のpropsとstateに対して常に同じ内容のDOMを描画する)であれば,React.addons.PureRenderMixinを使える
- shouldComponentUpdateを上書きする
- Mixinを定義するだけでいい
- propsやstateが複雑なobjectである場合は,比較そのものが重くなりうる
- → immutable data_structureを使うか,helper_functionを使う
- shouldComponentUpdateで,Reactにcomponentのlifecycle methodを呼び出す必要があるか教える
- immutablility helper_function
- React.addons.updateというhelper_functionにより,簡単にimmutableなdata_structureを使用できる
- first argument: object/array, second argument(option): hash object
- bottleneckを調べる方法
- React.addons.Perfを使うとわかる
- Developer Toolsのconsoleから,React.addons.Perf.start(); (終わるときは~.stop();)
- → ~.printWasted();でprofile結果を表示
- Wasted time: renderが呼び出されたにもかかわらず,実際のDOM内容が変わらなかった処理にかかった時間をcomponentごとに集計したもの
- React.addons.Perfを使うとわかる
- key attribute
- componentのclassよりさらに細かくinstanceを識別できる
- 不要な処理を避けるために使う
- key attributeの値が変更された場合,差分計算を行わずに即座にchild_componentを含めたすべてのvirtual_DOM objectを破棄し,一から再描画する
- listの要素の順番が変わったことをReactに伝える
- → 移動だけで済むようになる
- こちらの目的で使われることが多い
- 制限事項
- 同一階層のcomponent, 同一の親を持つcomponent間でunique要
- 要素が現在のparent_componentのlistと別のlistに移動したときは,同一性の追跡不可能
- component内部からpropsの値として参照できない
- 同一階層のcomponent, 同一の親を持つcomponent間でunique要
- まとめ
- shouldComponentUpdateを使用してperformanceを改善
- React.addons.Perfを使用して不要なrender呼び出しを特定
- key attributeを使用してReactの処理を最小化
Ch12 server_side_rendering
- 以下の問題への解決策
- search_engineのindexの対象にならない
- JavaScriptのロードを完了してからページを作成するので,初回のページ表示が遅い
- virtual_DOMのため,server_side_renderingが可能
- virtual_DOM: 単なるmemory上のdata_structure
- server_sideでvirtual_DOMを実際のDOMに反映する代わりにHTML文字列として出力する
- → 同じReact_componentをclient_serverで共用できる
- React.renderToString/React.renderToStaticMarkupの2関数
- server_sideにおける描画関数
- renderToString
- ほとんどはこっち
- 第2引数のtarget DOMが不要で,戻り値としてHTML文字列を返す
- sync_callで,非常に速く動作
- data-reactid
- browserでDOM_nodeを特定するために使う
- data-react-checksum
- server_side_renderingの場合にのみ追加される
- server_sideで作成されたDOMが再利用できるかどうかを判断する
- DOMの作成処理とそれをdocumentに挿入する処理を省略
- → 特に複雑なサイトではページの初期表示までの応答時間が著しく改善
- 作成するReact_componentの内容がserver_clientの間でまったく同じであることが特に重要
- root要素のみ
- renderToStaticMarkup
- 独自のdata attributeなし
- server_sideで描画したReact_componentをbrowserで再描画しない場合のみ
- HTML mailの作成
- 作成したHTMLを後でPDFに変換する
- componentのテスト
- renderToString
- server_sideにおけるcomponentのlifecycle
- renderより後のlifecycle methodは呼び出されない
- 特に,componentDidMount, componentはserver_sideでは呼び出されない
- → event_listenerの定義において,componentの終了を通知するlifecycle methodは存在しない前提で設計する
- → event_listenerやtimerは常にcomponentDidMountで登録して,componentWillUnMountで解除する
- componentWillMountはserver_clientいずれでも呼び出される
- renderより後のlifecycle methodは呼び出されない
- client_server両方で使えるcomponentの設計
- 同一のpropsとstateが与えられた場合,常に同じ内容を出力するようにcomponentを設計する
- → テストしやすく,server_clientで同じoutputを保証できる
- randomな値は外部からpropsとして受け取るようにする
- applicationの初期値をどのようにしてclient側に渡すか
- 最も簡単: JavaScriptのobjectとして初期値を渡す
- 同一のpropsとstateが与えられた場合,常に同じ内容を出力するようにcomponentを設計する
- async_data
- まずdataを取得して,そのcallback_functionでcomponentを描画する
- e.g.
- async_dataを取得する処理をstatics methodとして定義する
- props.initialStateとしてclientに渡す
- lifecycle method経由でasync_dataの変更を監視し,変更があった場合statics methodを使ってdataを再取得
- async_dataを取得する処理をstatics methodとして定義する
- Isomorphic(同型の) routing
- react-router
- Isomorphic JavaScript(: client_server両方のcodeをJavaScriptで記述することでコードを共有すること)を可能にする
- server_clientで同じAPIを提供するrouterを使ってroutingすること
- 既存のrouterでserver_sideでReact_componentを描画する場合,そのrouterはDOMのAPIに依存していないことが重要
- SEOの観点から重要なデータを取得するときは,routerのhandlerで非同期に取得して,top levelのcomponentから末端のcomponentへ順番に渡す必要がある
- 重要でないdataは,componentのcomponentDidMount methodでAJAXでdataを取得すればよい
- 常にclientでデータを取得
- Reactと併用するrouterを選定するときは,routerのhandlerでasyncにデータを取得してrenderingできるか注意する
- react-router
- singleton_object
- async_dataがsingleton_objectの状態に依存している場合,描画時にasync_dataが予期せぬ値になってしまう可能性がある
- 描画のたびにsingleton_objectをresetではなく,applicationを隔離されたcontextで実行する
- ContextifyのようなNodeのpackageなど
- Web Workersによく似ている
- 与えられたcodeをV8の異なるinstanceで実行する
- performanceは犠牲になる
- 実行contextをcomponent間で共有することは,非推奨
- componentの移植性が低下するため
- tradeoffがある
- ContextifyのようなNodeのpackageなど
- 描画のたびにsingleton_objectをresetではなく,applicationを隔離されたcontextで実行する
- async_dataがsingleton_objectの状態に依存している場合,描画時にasync_dataが予期せぬ値になってしまう可能性がある
- まとめ
- server_side_renderingは,Web applicationのSEOとperformanceの観点から有効な手段になる
- React_componentはserver_client両方でのrenderingが可能
- application全体がserver_side動作するように設計されている必要がある
Ch13 React_family
- Jest
- test runner
- Jasmineがベース
- Nodeのrequire()関数を書き換えて,すべてのCommonJS style moduleをmockに置き換える
- → すべてのcodeをテストできる
- Immutable.js
- React, Fluxと相性〇
- applicationのperformanceとsimplicityが改善
- 通常のJavaScript objectまたは配列を受け取り,独自のデータ構造に変換したものを返す
- 戻すこともできる
- object, arrayの比較が早くなる
- ===を使える
- Flux
- design pattern
- 厳密に単一のdataflowを規定
- 何にも依存していないので,気に入った部分だけ取入れられる
- まとめ
- Jestにより,Unit test時に依存moduleをmockに置き換える方法
- Immutable.jsを通常のデータ構造の代わりに使用する方法
- FacebookのFlux patternの概要
Part 3 tool
Ch14 build, debug
- Reactはcomponent単位の開発を容易にするため,いくつかの抽象的なlayerを設ける
- debug, release作業は複雑になる
- build_tool
- Reactでのapplication developmentにおいて,最も繰り返し実行される処理はJSXのパース処理
- そのほかに大部分を占める処理: 複数のmoduleをbrowserで実行するために単一もしくは少数のfileにまとめる(bundle)処理
- Browserify
- JavaScriptをpackagingするためのtool
- Node.js styleのrequire()呼び出しをbrowserでも使えるようになる
- requireされたすべてのmoduleを単一のJavaScript fileに連結(bundle)するのみ
- 単一のfile → browserで簡単にloadできる
- installと設定
- React projectの作成
- Watchify
- 変更時に自動でbuild
- buildの実行
- Webpack
- Browserifyと同じく,JavaScriptをpackaging + たくさんの機能
- BrowserifyがGruntやGulpと併用して実現する機能を単体で実現できる
- WebpackとReact
- 自身が依存するassetを内包するcomponentを作成できる
- assetがcomponentに紐づけられる → componentの移植性が高まる
- あるcomponentが使われなくなったときにその依存assetも削除
- どこからも参照されていないCSSや画像がなくなる
- Browserifyと同じく,JavaScriptをpackaging + たくさんの機能
- Reactでのapplication developmentにおいて,最も繰り返し実行される処理はJSXのパース処理
- debug_tool
- React Developer Tools
- Chrome拡張機能
- displayName
- JSXがJavaScriptに変換されるときに,componentの定義に自動で追加される
- そのほか多くの情報を見ることができる
- JSBinとJSFiddle
- online demo site
- React Developer Tools
- まとめ
- React developmentにおいて,build, debug toolがいかに有用であるか
Ch15 test
- TDDのworkflowでコードをmodule化し,変化に強くし,より安全にコードベースを変更できるようにする
- はじめに
- testにより,よりよいコードを書けるようになる
- 単一責任の原則や,デメテルの法則にしたがうことになる
- testの種類
- unit_test
- E2E_test
- test_tool
- testにより,よりよいコードを書けるようになる
- 初めてのtest: render method
- testでは,React.renderの代わりにReact.addons.TestUtils.renderIntoDocumentを使う
- ReactにおけるHTMLの検査
- Reactでは,componentのrender methodで指定したHTMLは,実際のDOMとは異なる
- componentのmock
- 対象のcomponentの機能だけをテストする
- 前処理,後処理
- beforeEach, afterEach
- 要約
- mock componentを定義する
- componentのローカル変数の値を保存する
- ローカル変数の値を書き換える
- testを実行する
- ローカル変数の値を元の値に戻す
- Jasmineのhelper moduleでspec間の共通の処理を記述できる
- (mockの内容はp.147の下段)
- npmを使わないvanilla projectのcase
- functionのstub化
- stub化の目的
- unit_testの対象範囲の限定
- 関数内で使われているAPIやthird_partyのserviceなどの処理がテスト中に実行されるのを避ける
- その関数が正しい呼び出し元から正しい引数で呼び出されていることをチェックしたい
- jasmine-react-helpers
- spyOnClass
- stub化のmethod例
- ランダム
- serverからdataを取得
- testで再現困難なstateを参照する
- 副作用の範囲が大きい
- 現在時刻やtimezoneを扱う
- callback_functionのテスト
- test→実装の流れ
- stub化の目的
- event simulation
- test→実装の流れ
- testにおけるcomponentのselector API
- Mixinのテスト
- Mixinを直接テストする
- Mixinの内部で呼ぶReactのmethodをすべてスタブ化必要
- とても細かいテストになる
- 機能が複雑な場合は利点もあるが,機能ではなく実装そのもののテストになってしまう状況になる
- Object.createでテストごとにMixinを新たにcopyする方法
- Reactの機能はスタブ化する
- Reactのlifecycle methodの呼び出し順を忠実に再現が必要になる
- dummy_component経由でMixinをテストする
- 非常にsimpleなcomponentであり,テストの意図がより明確になる
- 唯一の難点: Reactの制限によりrender methodを必ず実装する必要がある
- componentが画面から削除されたときにclearIntervalが呼び出されることを保証したい
- → componentWillUnMountを直接呼び出すのではなく,componentを画面から削除してReactに適切なcallbackを実行させることが重要
- まずは直接の方式でテストを書いてみて,困難な場合はdummy_component経由に書き直すのが〇
- 共有スペックを記述する
- testの記述先がMixinのspec_fileではなくMixinを使用するcomponentのspec_fileになる
- 複数のcomponentから使われるので,共通部分は共有スペックに記述する
- Mixin内の呼び出しをテストするためであり,Mixinを使うcomponentからの呼び出しのテストではないので,idを分ける
- ほかからの影響を受けやすく,より複雑になる
- 適している場面
- Mixinを使うときにcomponentが特別なmethodを実装する必要があるとき
- componentがそれらのmethodを正しく実装しているか,共有スペックでテストできる
- Mixinとcomponentの間のinterfaceをテストできる
- Mixinの提供する機能がcomponent側で上書きされることで破壊される可能性がある場合,共有スペックによりそれを検出できる
- Mixinを使うときにcomponentが特別なmethodを実装する必要があるとき
- Mixinを直接テストする
- \<body>に対する描画
- renderIntoDocumentを使う意図: pageと切り離されたDOM_nodeに対して描画を行うため
- 可能な限りこちらを使う
- 実際にcomponentがpageに描画される必要があるときは,renderを使う
- 親のDOM_nodeに対s手行った変更を注意深く元に戻す必要がある
- jasmin-react-helpersを使うと,テスト終了時に自動でcomponentを削除してくれる
- renderIntoDocumentを使う意図: pageと切り離されたDOM_nodeに対して描画を行うため
- server_sideのテスト
- Mochaを使う
- Nodeのecosystem内でとても有名で,非同期処理をうまく扱える
- spec_fileのtemplate
- npm run test-server
- doneでassertionの完了を知らせる必要
- chain上で呼び出す
- SuperTest
- CheerioでHTMLとしてパースしてassertする
- 404のテスト
- Mochaを使う
- browserを使ったテストの自動化
- E2E_testについて
- end_userの観点からapplicationの機能の正しさを検証するテスト
- 基礎
- browserを操作してWeb pageの内容が正しいか検査する
- CasperJS
- browserを簡単に操作するためのtool
- 内部的にPhantomJSを使っている
- PhantomJS
- JavaScriptから操作可能なheadless browser
- rendering engineとしてWebkitを使っている
- headless browser
- 画面に何も表示しない
- terminalからcommand経由で操作できる
- testで行うbrowser操作
- linkのclick, formの記入, URLの入力, drag and dropなど,userが通常行うbrowser操作
- Webkit
- Safariで使用されるrender engine
- ChromeはWebkitをforkしたBlinkというrender engineを使っている
- FirefoxはGeeko
- Internet ExplorerはTrident
- CasperJSでのテストがどのようなものか
- end_userの視点でbrowserを操作 → Reactの文字は出てこない(Reactを使っているかどうか関知しない)
- testが始まる前にnpm startでapplicationを起動する必要がある
- リンクのクリック
- thenのコールバック関数の中でテストを実行する
- serverの起動
- 自動的にserverを起動するためのscript
- spec_fileのポート番号を変更する
- E2E_testについて
- まとめ
- テストに関連するさまざまな概念について
- 描画のテスト
- 関数のスタブ
- componentのmock
- Mixinのテスト
- componentの検索
- server_sideでのテスト
- E2E_test
- テストに関連するさまざまな概念について
Part 4 実践
Ch16 architecture pattern
- Reactをほかのframeworkやarchitecture patternと併用してapplicationを構築する方法を見る
- routing library
- single_page_applicationにおいて,routerはURLをハンドラにマッピングするためのモジュール
- Backbone.Router
- Backbone: single_page_applicationを開発するためのlibrary
- MVW(Model-View-Whatever)の形態
- Backbone: single_page_applicationを開発するためのlibrary
- Aviator
- router機能のみを持つstand alone library
- 複数のtargetを指定できる
- react-router
- routerの定義自体がReact_componentで構成される
- path属性に基づいてrouting, 該当するRouteのhandler属性に指定されたcomponentを描画
- Link component
- page navigationに使える
- Om(ClojureScript)
- 永続データ構造を提供
- → Omはapplication全体を高速にrendering
- snapshotを容易に取得
- → undoのような機能を簡単に実装できる
- 永続データ構造を提供
- Flux
- Facebookにより考案されたarchitecture pattern
- 単一方向のdataflowを強制
- → Reactとともに使うことでapplicationの動作を推測しやすくなる
- 大きな変更が不要.容易に導入
- Store/Dispatcher/View(React_component_tree)で構成
- Actionを4つ目のパーツとみなせる
- Action: 補助的なmethodを提供しDispatcherのinterfaceとして機能する
- Actionを4つ目のパーツとみなせる
- 最上位のReact_componentはController-ViewとしてのRoleを担う
- Storeとchild_componentとの仲介役として機能する
- (iOSのViewControllerとは全く別物)
- Storeとchild_componentとの仲介役として機能する
- 各パーツは独立 → 関心の分離を強いられる → 個別テスト容易
- dataflow
- 情報が一方向に流れる
- merit
- applicationの動作が推測しやすい
- application stateを1か所に集めて管理できるようになる
- application stateはStoreに集約され,すべてのdataの取得/更新はStoreで管理
- Fluxを構成するパーツ
- Dispatcher
- applicationの中心的なRole
- すべてのデータがいったんDispatcherを通る
- singleton_object
- callback経由でStoreにイベントを通知
- 複数のcallback_functionの依存関係の管理はDispatcherの責務
- userやnetworkからの入力を登録しているすべてのStoreに通知し,各Storeがそれをチェックして自身に関係のあるinputのみを処理する
- Action
- user視点での入口
- userがUIに対して行った操作はAction経由でDispatcherに届けられる
- DSLとして機能する
- 1段階高いレベルの言語へと翻訳され,Storeが意味を理解できるActionに変換される
- userの操作はcomponent_treeをさかのぼってDispatcherに届けられる
- その過程で,userの操作はapplication固有のActionに変換される
- Store
- applicationのデータのやりとりを一手に引き受け,developerはここにbusiness_logicを記述する
- Dispatcherに登録したcallback_function経由でActionの通知を受け,自身の管理するデータに関係のあるActionの場合のみ応答する
- dataが更新された場合,change eventを発行してReact_component_treeに更新を通知する
- applicationのほかの部分からは厳密に分離
- Storeはapplicationのすべてのデータを保存
- applicationのほかの部分はデータの操作方法を知らない.Storeはapplicationで唯一データの変更が行われる場所になる
- Storeはgetter methodのみサポートし,setter methodを持たない
- dataの変更はすべてDispatcherからのcallback経由で行われる
- Controller-View
- Viewのtreeの最上位のcomponentがStoreとのやりとりを受け持つ
- componentはController-Viewと呼ばれる
- 規模が大きくなると複数のController-Viewとなることもある
- Viewのtreeの最上位のcomponentがStoreとのやりとりを受け持つ
- Dispatcher
- 複数のStoreを管理する
- 変更内容
- DispatcherはActionをqueueに格納するように変更
- DispatcherはActionの処理が完了するまで処理を停止できるように変更
- Dispatcherにcallbackを登録する際に,どのActionに対して待ち受けるか指定できるようにする
- Dispatcherの改善
- Dispatcherの返すidに対してWaitFor
- 変更内容
- まとめ
- Reactをほかのframework/architecture patternと併用してapplicationを構築する方法
- MVC framework ~ Flux patternまで,Reactの高い順応性
- Reactをほかのframework/architecture patternと併用してapplicationを構築する方法
Ch17 そのほかのusecase
- React: interactiveなUIを構築するための非常に強力なrendering library
- Web application以外の分野にも適用可能
- Reactが提供するデータおよびuser inputを処理する方式や,再利用可能でテスト容易な小さいcomponentを複数組み合わせてapplicationを構築するやり方
- desktop application
- atom-chellやNW.jsなどによる
- desktop上のinteractiveなapplicationを構築するためにReactを使える
- game
- gameは本質的にstate machineで,以下の基本的なRoleを持つ
- 画面の更新
- eventへの反応
- Reactは以下の2点に対してのみ責任を果たす
- DOMの更新
- eventへの反応
- Reactのvirtual_DOMの方式は,高性能のgame engineから着想を得たもの
- 2048の例
- immutable method
- dataの共有
- 不要な状態更新を避ける
- 柔軟な構造 → undoを簡単に追加できる
- ReactによりViewの動機を気にすることなくgame_logicとplayerとのやり取りに集中できる
- gameは本質的にstate machineで,以下の基本的なRoleを持つ
- HTML_mail
- React.renderToStaticMarkupを使う
- 与えられたcomponent_treeをHTML文字列に変換
- 独自のデータ属性を出力しない ←→ renderToString
- 実装例
- CSSファイルの追加
- 再利用・テスト可能なcomponentを組み合わせてinteractiveなUIを構築できるという利点をHTML_mailでも得られる
- React.renderToStaticMarkupを使う
- data_visualization
- まとめ
- 以下を見た
- Reactはbrowserで動作するWeb applicationだけでなく,desktop applicationやHTML_mailの作成にも使える
- game developmentでReactを利用する方法
- D3のようなlibraryと併用してdata_visualizationの用途で使用する方法
- 以下を見た
Appendix A 開発環境構築について
- Reactは開発版と製品版がある
- & アドオンありなし
- Nodeの使用
- Nodeのpackage management toolであるnpmを中心に,frontend developmentのための様々なtoolのecosystemが形成されているため
- Nodeを使わない開発環境構築手順,react-tools
- JSXTransformer/react-tools
Appendix B API reference
- 3種類
- 用語の整理
- component仕様
- React.createClass()に引数として渡すobject
- render methodなどのlifecycle methodを定義する
- component class
- React.createClass()の戻り値として得られるobjectか,またはES6 class.
- JSXにタグ名として直接記述するか,React.createElement()の引数として渡す
- ReactElement
- React.createElement()の戻り値として得られるobject
- 内部的にはすべてのcomponent classはReactElementに変換される
- React.render()の第一引数やrender methodの戻り値において使用される
- component instance
- ReactElementをもとにReactが生成するobject
- component仕様で定義したmethod内で,this経由で参照できる
- 外部からcomponent instanceにaccessするために,React.render()の戻り値もしくはref属性経由で参照を取得する
- component仕様
- top level API
- React
- libraryとしてのentry point
- React.createClass
- React.createElement
- React.createFactory
- React.render
- React.unmountComponentAtNode
- React.renderToString
- React.renderToStaticMarkup
- React.isValidElement
- React.findDOMNode
- React.cloneElement
- React.DOM
- React.PropTypes
- React.initializeTouchEvents
- React.Children
- React.Children.map
- React.Children.forEach
- React.Children.count
- React.Children.only
- React
- component API
- setState
- replaceState
- forceUpdate
- getDOMNode
- isMounted
- setProps
- replaceProps
- component 仕様
- object
- propTypes
- mixins
- statics
- displayName
- lifecycle method
- render
- getInitialState
- getDefaultProps
- componentWillMount
- componentDidMount
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- componentDidUpdate
- componentWillUnMount
- object