TokyoFacebookTwitterHatenaPocket人気のデータビジュアライゼーションライブラリー「D3.js」をもっと使いやすく、便利にするために。Reactを使ったコンポーネント化に取り組み、リアルタイムで描画されるアニメーションを作ります。Webのデータビジュアライゼーション分野におけるjQueryのように、考えられるあらゆることが実現できます。オンラインで見られる最良のWebのデータビジュアライゼーションの多くがD3を使用しています。D3は素晴らしいライブラリーですが、最近のv4のアップデートで従来よりさらに安定性が増しました。Reactと一緒に使えば、D3はさらに便利になります。jQueryのように、D3は高性能ですが課題もあります。データビジュアライゼーションが大規模になればなるほど、用いるコードは複雑になり、バグを修正したりアイデアを絞り出したりするのにさらに時間がかかるようになります。Reactを使えばそれを解決できます。ES6』を読めば理解が深まり、またReactとD3の最良の統合方法に関する情報も書いてあります。実例を用いて、宣言型トランザクションベースのアニメーションを実装する方法を説明します。』としてYouTubeにも掲載されています。Reactは有用か?たしかにReactは大規模です。Reactを使用するとコード量が大きく増加し、さらにそれに伴う負荷が増大します。アップデートし続けなければならないライブラリーが1つ増えるということにもなります。効果的にReactを使用したいなら、ビルド手順が必要です。なんらかの手段でJSXコードを純粋なJavaScriptに変換します。現在では、WebpackとBabelのセットアップは簡単です。create-react-appを実行するだけです。セットアップが終わればJSXのコンパイル、最新のJavaScriptの機能、リンティング、ホットローディング、製品ビルドのためのコード縮小などが使用できます。サイズが大きくツールも複雑ですが、データビジュアライゼーションに取り組んでいる場合は特に、Reactを導入する価値があります。メンテナンスやデバッグ、拡張をしなくてもよい単発のプログラムを開発している場合は、純粋なD3にこだわってください。実用向けのアプリを開発している場合は、Reactの追加を勧めます。メリットは、Reactがコードのコンポーネント化を強く促す点です。コンポーネント化によって間接的・直接的にさまざまなメリットがでてきます。D3コードと一緒にReactを用いる主なメリットを以下に示します。コンポーネント化テストとデバッグを容易にするスマートなDOMの再描画ホットローディングコンポーネント化をすると、一連の論理ユニット、すなわちコンポーネントとしてコードがビルドされます。ように、HTML要素であるかのように使用できます。次のセクションで深く掘り下げます。一連のコンポーネントとしてデータビジュアライゼーションをビルドすれば、テストやデバッグが容易になります。1度に1つの論理ユニットに集中できるようになります。ここでコンポーネントが動作すれば、同様にほかの場所でもそのコンポーネントが動作するということです。呼び出されても、やはり問題なくテストをパスするはずです。Reactはコードの構造を理解しており、変更のあったコンポーネントだけを再描画する方法を知っています。なにを再レンダリングして、なにをそのままにしておくかを決める面倒な作業はもう必要ありません。変更して忘れてしまえば良いのです。Reactは自身でそれを把握します。プロファイリングツールを見れば、変更のあった箇所のみが再レンダリングされていることが分かります。create-react-appを使用してツールを構成すれば、Reactはホットローディングを利用できます。ここで、3万ものデータポイントを持つデータビジュアライゼーションをビルドするとします。純粋なD3を使用した場合、コードの変更があるたびにページを更新しなくてはなりません。データセットを読み込み、データセットを解析し、データセットをレンダリングし、テストの状態になるようにあちこちクリックして......あくびが出そうです。Reactを使えば、再読み込みしたり待機したりする必要がありません。ページ上で即座に変更されます。動作中のReactを見たときはとても衝撃的でした。データビジュアライゼーションのコードは動作しています。それをビルドしてリリースすれば、人びとは幸せになります。コンポーネントを使用すれば、それが可能です。しやすい整理されている流行りの言葉の羅列に見えるかもしれませんが問題ありません。説明していきましょう。宣言型コードとは、どうしたいのかではなく、なにをしたいのかを示すコードのことです。あれば、すでに宣言型コードの書き方が分かっています。おめでとうございます!ReactはJSXを使って、JavaScriptをHTMLのような見た目にします。それは裏側で純粋なJavaScriptにコンパイルされます。次のコードがなにをするのか予想してみてください。)}「4つのヒストグラムをレンダリングする」と予想していたら、正解です。おめでとうございます。ヒストグラムコンポーネントを生成したあとは、通常のHTML要素と同様に使用できます。/>タグを挿入した場所に表示されます。この場合のパラメーターはxおよびy座標、widthとheightのサイズ、title、いくつかのdata、アクセサのvalueとなります。それぞれのコンポーネントに必要な値を指定可能です。パラメーターはHTML属性のように見えますが、関数を含む、どんなJavaScriptオブジェクトでも指定できます。パワーアップしたHTMLのようです。いくつかのひな型と適切なデータセットを使用すると、先ほどのコードでこのような画像が表示されます。ソフトウェア制作に携わる人のカテゴリ別の給料分布を比較しています。一度コードを見てください。/>がヒストグラムを作成する関数であるかのようです。Histogram()).render()、または同様のなにかにコンパイルされます。/>を使用するたびに、インスタンスのrender関数を呼び出します。Reactコンポーネントは関数プログラミングの原則に従う必要があります。ルールを破りたくなければ、副作用がなく、ステートレスで、何度実行しても結果が同じで、同等性を持つようにしなければなりません。JavaScriptの関数では、これらの原則を守るのに相応の努力が必要ですが、Reactでは原則を守らないようにコーディングすること自体が困難です。それこそがチームで作業する際のメリットです。宣言型かつ再利用可能なので、コードははじめから理解しやすくなります。HTMLを使用したことがあれば、コードがなにをするのか理解できます。詳細が分からないこともあるかもしれませんが、HTMLとJavaScriptをある程度知っていれば、JSXの読み方が分かるはずです。複雑なコンポーネントはより単純なコンポーネントで構成され、そのコンポーネントはさらに単純なコンポーネントで構成され、そのコンポーネントは最終的に純粋なHTML要素で構成されます。することで、コードは整理された状態で保たれます。半年経ってからコードを見ても「ああ、これは4つのヒストグラムだな。これを調整するには、ヒストグラムコンポーネントを開いて手を加えれば良いはずだ」と理解できます。Reactは、私のお気に入りの関数型プログラミングの原則を採用し、それらを実用的にしてくれます。私はそこが気に入っています。それでは、アニメ化されたアルファベットの例を見てください。アニメ化されたアルファベット例アニメ化されたアルファベットのビルドです。ReactとD3を一緒に使用するもっとも単純な例だからというわけではなく、かっこよく見えるからです。講演でこれを見せるときはいつも、特に変更があったDOM要素のみが再描画されることを証明すると観客からどよめきが起こります。React』の要約版です。短くまとめるために、記事ではいくつかの詳細にはあまりきちんと触れません。GitHubレポジトリでコードベース全体を見られます。4.0.0をベースにしています。クラスのプロパティなど、使用している構文のいくつかはまだ安定版のES6に存在しませんが、ツールのセットアップにcreate-react-appを使用すれば動作するはずです。————アニメ化されたアルファベットを作成するには、以下の2つのコンポーネントが必要です。SVGテキスト要素をレンダリングし、自身のトランザクションの開始、更新、終了を管理するSVG要素のレンダリングにReactを使用し、トランザクションやインターバル、そして数学関連の処理のためにD3を使用します。AlphabetコンポーネントAlphabetコンポーネントは現在の文字リストを保持しており、ループ内でLetterコンポーネントの集合をレンダリングします。以下のような骨組みから始めます。Alphabet;関連するものをインポートし、少し整形し、Alphabetコンポーネントを定義します。そこで、静的なlettersプロパティでは利用可能な文字リストが保持され、コンポーネントのstateでは空のalphabetが保持されます。componentWillMountとrenderメソッドも必要です。1.5秒ごとに新しいアルファベットを生成するのに最適な場所はcomponentWillMountの中です。1500)を使います。ピリオドごとに利用可能な文字をシャッフルし、ランダムな数だけ取り出して並べ替え、setState()を使ってコンポーネントのstateを更新します。これでランダム順とアルファベット順の両方が実現できます。setState()をきっかけに再レンダリングします。宣言型コードの魔法はrenderメソッドで体験できます。Letterコンポーネントの集合をレンダリングします。各Letterは現在のテキストdと、インデックスiを取得します。key属性を使用してReactにどのコンポーネントがどれを指すのか認識させます。ReactTransitionGroupを使うと、特別なコンポーネントライフサイクルメソッドを使って滑らかなトランジションを実現できます。ReactTransitionGroupいつコンポーネントがマウントされて、更新されて、アンマウントされるかを通知する通常のライフサイクルフックに加えて、ReactTransitionGroupを使うとcomponentWillEnter、componentWillLeaveなどにアクセスできます。なにか見覚えのあるものがありませんでしたか?componentWillEnterはD3の.enter()と同じで、componentWillLeaveはD3の.exit()と同じ。componentWillUpdateはD3の.update()と同じです。「同じ」は強い概念であり、類似しています。D3のフックは、Reactのフックが各コンポーネントで個別に動作している間に、セレクション全体、すなわちコンポーネントのグループで動作します。D3ではなにが起こるかオーバーロードで指示しますが、Reactでは各コンポーネントがなにをするのかを知っています。これにより、Reactのコードがより理解しやすくなると考えられます。ReactTransitionGroupでさらにたくさんのフックを使用できますが、これら3つすべてが必要です。良い点は、componentWillEnterとcomponentWillLeaveの両方で、コールバックを使用して「トランザクションが終了して、Reactが返ってきた」とはっきり言えることです。Tilleyに感謝します。Letterコンポーネントさあ、すてきなもの、宣言型データビジュアライゼーション、あるいはデータビジュアライゼーション自身を遷移できるコンポーネントを作る準備が整いました。Letterコンポーネントのための基本的な骨組みは以下のようになります。Letter;はじめに関連するものをいくつか記載し、Letterコンポーネントをデフォルトのstateおよびデフォルトのトランザクションで定義します。場合は、連携や一時プロパティのためにstateの使用を避けたいと考えるでしょう。そのためにpropsがあります。transitionと一緒にstateを使用すると、D3の実動作とReactの実動作の同期が保たれます。した魔法のデフォルト値はデフォルトのpropsになります。これによってより柔軟にAlphabetを生成できます。componentWillEnterトランザクションの開始をcomponentWillEnterに格納します。selectionへ変換します。いまはD3でできることすべてがコンポーネントで実現できるのです。やりましたね!そして現在のインデックスと文字の幅を用いてthis.state.xを更新します。xをstateに入れると、コマ落ちを防げます。iプロパティは更新のたびに変化しますが、Letterの移動を遅延させたいのです。Letterは初回のレンダリング時、非表示であり、ベースラインから60ピクセル上部に存在します。それを下に移動させて表示させるには、D3トランザクションを使います。node.transition(this.transition)を使用して、以前のデフォルト設定で新しいトランザクションを開始します。すべての.attrと.styleは時間の経過とともに生じた内容をDOM要素自身で直接変更します。するとReactに混乱が生じます。それがDOMをコントロールしているからです。...)を使ってReactの動作を実際の動きと同期させなければなりません。setState()を使用して、コンポーネントのstateを更新し、メインのcallbackを呼び出します。Reactはこのとき、この文字が表示されているということを認識しています。componentWillLeaveトランザクションの終了はcomponentWillLeave()です。先ほどの内容とはちょうど逆になります。}このとき、stateをxの代わりにclassNameに変更します。これはxが変化しないためです。トランザクション自身の終了とは、開始の逆を意味します。文字が下に移動して非表示になるということです。トランザクションの終了後に、コンポーネントを削除して良いことをReactに伝えます。componentWillReceivePropsトランザクションの更新はcomponentWillReceiveProps()です。stateを更新しトランザクションを実行して、stateをトランザクションのあとの実動作と同期させます。この場合classNameを変更して、それから文字を新しい水平位置に移動します。renderトランザクションの動作がすべて終わったあとに、「どうやってこれをレンダリングするんだろう?」と思うでしょう。気持ちは分かります!しかし、面倒な作業はすべて終わりました。レンダリングは以下のとおり簡単です。y)でレンダリングされたSVG<text>要素を返します。すると、dプロパティによって得られた単一の文字が表示されます。述べたように、x、y、className、fillOpacityにstateを使用するのは理論的には誤っています。通常はそれらに対してpropを使用します。stateはrenderとライフサイクルメソッドの間のでやりとりをするためのもっともシンプルな方法だと考えられます。基礎を終えて流行だといえばそのとおりです。アニメ化された宣言型ビジュアライゼーションのビルド方法が分かりました。言ってもらえると、とてもうれしいです。以下が動作の中でどのように見えるかは次のとおりです。すてきなトランザクションなど、実行すべきものはすべて配列内でループし、いくつかの<Letter>コンポーネントをレンダリングします。最後にこれで、技術的判断を下すために必要なReactに関して十分理解できたはずです。プロジェクトを見て、「たしかにこれは使い捨てのおもちゃよりも良い。コンポーネントは便利だし、デバッグが簡単で助かる」と判断できます。うれしいことに、ReactとD3を一緒に使って宣言型アニメーションをビルドする方法も理解できたはずです。従来は至難の業でした。ES6』を読んでください。