Topics

・関数型プログラミングとオブジェクト指向のパラダイムとしての対立 国内の【自称】関数型コミュニティと海外の論調の違い

ガラパゴス・ネットスラング=「関数型ポエム」という呪詛、先入観的読書と、フェアなレビューの登場

Qiitaの騒動から派生して、東北大学の住井 英二郎@esumii氏、らくだの卯之助@camloeba氏その他が、犯罪者集団に合流して2ちゃんねるでの誹謗中傷チームの「8賢者」「ウィザード組」とかアホなことをやってる件について

JavaScriptではES6+とReact-JSXからES5へのトランスパイルが標準に / ATOMエディタで最速環境構築 厳選パッケージ 3 + 3 2015年夏バージョン

2016年のnode、ES6、React、Babel、Atomエディタ界隈の方向性

Dockerじゃないsystemd-nspawn+machinectlが非常に良い

99%のプログラマがIQ145のJKに「ダサい」と言われてしまう理由とは?【その1】「計算機科学のほんとうの基礎」を理解していない。IQ145のJKと同じ事を語るMITの権威とSICPという聖典の権威を借りてマインドコントロールを解いてみよう

99%のプログラマがIQ145のJKに「ダサい」と言われてしまう理由とは?【その2】関数型プログラミングのイミュータブルな世界観とイミュータブルな実世界を完全に統合

10年先を行く斬新な関数型(FRP)データベースについて説明する 99%のプログラマがIQ145のJKに「ダサい」と言われてしまう理由とは?【その3】

[React (.js Facebook)解説 関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間 サポート記事【静的HTML編】React 解説【動的HTML-FRP編】

量子コンピュータが超高速である原理と量子論とそれに至るまでの科学哲学史をゼロからわかりやすく解説01量子コンピュータが超高速である原理と量子論とそれに至るまでの科学哲学史をゼロからわかりやすく解説02

『関数型プログラミングに目覚めた!』のレビュー(Day-1)について

LISPデータ構造の問題点の指摘と抜本的解法としての新プログラミング言語の策定/純粋関数型言語「SPINOZA」

著書『関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間』 [Day1]たち読み記事 無料公開中

『関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間』を大変多くの方々にお買い求めいただき、感謝します。本書の全目次を公開し、質問を受け付けます。

2015年4月24日金曜日

React (.js Facebook)解説 関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間 サポート記事 静的HTML編

関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間
enter image description here
で、内容の流れ、紙面、諸々の都合で書ききれなかった、React (.js Facebook)の補足解説で、本書の読者のためのサポート記事です。
著書では、前章からの流れを受けて、関数型プログラミングの考え方とReact公式ページによる導入を踏まえてReactを解説していますが、この記事はその延長かつ、別方向からの切り口での補足解説記事という位置づけです。
広い読者に向けて、この記事単独でもReactに入門できるように(なるだけ)書きます。

原始のWebのHTML 【宣言型コード】

HTMLコード
<html lang="ja">
 <body>
  <div>
   <h1 lang="en">HyperText Markup Language</h1>
   <p>HTMLは、<a href="http://ja.wikipedia.org/wiki/SGML">SGML</a>
      アプリケーションの一つで、ハイパーテキストを利用してワールド
      ワイドウェブ上で情報を発信するために作られ、
      ワールドワイドウェブの<strong>基幹的役割</strong>をなしている。
      情報を発信するための文書構造を定義するために使われ、
      ある程度機械が理解可能な言語で、
      写真の埋め込みや、フォームの作成、
      ハイパーテキストによるHTML間の連携が可能である。</p>
  </div>
 </body>
</html>
上記のHTMLコードをブラウザで表示(実行)すると、以下のような結果になります。


HyperText Markup Language


HTMLは、SGML
アプリケーションの一つで、ハイパーテキストを利用してワールド
ワイドウェブ上で情報を発信するために作られ、
ワールドワイドウェブの基幹的役割をなしている。
情報を発信するための文書構造を定義するために使われ、
ある程度機械が理解可能な言語で、
写真の埋め込みや、フォームの作成、
ハイパーテキストによるHTML間の連携が可能である。


HTMLは、
文書構造を定義する
宣言型コードであり、タグの入れ子構造と上下関係で、文書が定義されます。
あくまでWebページ=文書という静的な対象を定義するためのコードで、HTMLコードの上下関係→文書の上下関係と物理的に対応しています。HTMLコードの構造は単純明快です。
enter image description here

進化したWebのHTML+JavaScript 【命令形コード】

Webはあっという間に世界中に普及して、
静的なWebページ=文書

動的なWebアプリケーション=ユーザ・インタフェース
へと進化しました。
土台となる、静的で宣言型である、
コードの各要素(エレメント)を、オブジェクト指向のオブジェクトとして扱い、JavaScriptで動的に操作するという命令形プログラミングになりました。
enter image description here

さらに進化した次世代WebのReact JSX(HTML+JavaScript) 【宣言型コード】

動的なWebアプリケーション=ユーザ・インタフェースは、洗練され複雑化していきました。
Facebookは肥大化、複雑化する自サイトを再構築するために、新たな技術Reactを開発します。
Reactは関数型プログラミングの潮流にあり、コンポーネント指向の宣言型コードでWebアプリケーションを構築します。
かつては、HTMLで宣言的に記述して、JavaScriptで動的に操作していた、分断されていた構造は、Reactでは、JavaScriptを拡張したJSX言語で統合的に宣言型コーディングします。
HTMLはWebの既存のプロトコルとして、JSXを起動する枠組みだけが残ります。
enter image description here
この図のように、React JSXで、統合的に宣言型コーディングすると何故良くなるのか?というのは、何故、関数型プログラミングが良いのか?というのとまったく同じ事を語ることであり、まったく同じ理由なので、その辺りは延々と本稿の冒頭で引用している記事やその延長の著書で解説しているのでそちらを参照してください。
動的なWebアプリケーション=ユーザ・インタフェースを、静的な宣言型コードで書くために必要なのは、関数型プログラミングの潮流にある関数型リアクティブプログラミング(FRP)の手法です。
ReactはFRPの機能が実装されています。
FRPは著書でも関数型プログラミングの考え方、命令型プログラミングとオブジェクト指向からのパラダイムシフトとして解説していますが、重大な発想の転換が必要です。
Reactを理解するには、
1.HTMLからJSXへの移行
2.JavaScriptからFRPを伴うJSXへの移行
と複数の要素があるのですが、本稿では、特にFRPを必要としない静的なドキュメントを、HTMLからJSXへ移行させる基礎固めに、まず注力し、その後でFRPも含めて解説します。

静的なドキュメントをHTMLからReact JSXに移行、最初の一歩

HTML

単純なHTMLコード
classic00.html
<div>Hello</div>
表示結果

Hello

をJSXに移行させます。

React JSX

まずは、単にReact JSXを起動する枠組みだけのHTMLを用意します。
react00-0.html
<!-- The core React library -->
<script src="http://fb.me/react-0.12.1.js"></script>
<!-- In-browser JSX transformer, remove when pre-compiling JSX. -->
<script src="http://fb.me/JSXTransformer-0.12.1.js"></script>

<script type="text/jsx" src="react00-0.js"></script>
react00-0.js ←JSX
var HelloComponent = React.createClass(
{
  render: function()
  {
    return (<div>Hello</div>);
  }
});


var mount = React.render(<HelloComponent/>, document.body);
表示結果

Hello

ファイル名をreact00-0.jsとしていますが、
JavaScriptを拡張したJSXのコードであり、拡張子もjsxとしても構わないですし、そろそろそのような作法が推奨されてきています。
React JSXでは、コードの最後に必ず唯一の、document.bodyあるいはその他のHTMLドキュメント部分に唯一ReactのElement(エレメント)をマウントする宣言で終わります。
var mount = React.render(<HelloComponent/>, document.body);
上のコードでマウントしているElementは、
<HelloComponent/>です。

React JSXのElement(エレメント)は、ファーストクラス・オブジェクト

React JSXのElementはJSX上では、
<HelloComponent/>というように、従来のHTML(あるいはXML)のタグとまったく同じ表記ですが、JavaScript(JSX)のコード内でシームレスに、ファーストクラス・オブジェクトとして扱われます。
<HelloComponent/>は、ファーストクラス・オブジェクトであるので、普通に、
var HelloComponentEL = <HelloComponent/>;
というように、任意の変数として定義もできます。
var mount = React.render(<HelloComponent/>, document.body);
は、
var HelloComponentEL = <HelloComponent/>;

var mount = React.render(HelloComponentEL, document.body);
と、書くことも出来ます。

ReactのComponent(コンポーネント)

<HelloComponent/>というReactのElement(エレメント)は、
オブジェクト指向のオブジェクトのインスタンスに似ており、
その背後の設計としての
オブジェクト指向のオブジェクトのクラスに似た存在があります。
それが、ReactのComponent(コンポーネント)です。
<HelloComponent/>というReactのElement(エレメント)の背後にある、ReactのComponent(コンポーネント)は、タグ表記部分を外した、HelloComponentとして、
オブジェクト指向のオブジェクトのクラスのように、設計します。
var HelloComponent = React.createClass(
{
  render: function()
  {
    return (<div>Hello</div>);
  }
});
逆に言うと、設計したReactのComponentをタグ表記にすることで、ReactのElementに「インスタンス化」することができます。

ReactのComponent(コンポーネント)指向をオブジェクト指向との類似で理解し、オブジェクト指向との明確な差異を理解する

Reactはコンポーネント指向であり、
オブジェクト指向のオブジェクトのクラスとインスタンスにあえて類比させると、
Reactの
Component(コンポーネント)は、オブジェクトのクラス
var HelloComponent = React.createClass(
{
  render: function()
  {
    return (<div>Hello</div>);
  }
});
Element(エレメント)は、オブジェクトのインスタンス
<HelloComponent/>
と類比することができます。
以上はあくまで導入のための類比部分で、以下に差異を説明します。

ReactのComponent(コンポーネント)は、必ず、なんらかのElement(エレメント)を返す関数

オブジェクトと決定的に異なるのは、
Reactの
Component(コンポーネント)は、
必ず、なんらかのElement(エレメント)を返す、
 render: function()
  {
    return (<div>Hello</div>);
  }
ということです。
これは、関数型プログラミングにおいて、
すべての関数が、必ずなんらかの返り値を返す、
という仕組みとまったく同じであり、
コンポーネント指向のコンポーネントとは、
関数型プログラミングの関数と振る舞いが同一であるということです。
コンポーネント指向のコンポーネントとは、
何らかの入力を受けて何らかの出力を返す、関数であり、
Reactの場合、その出力は、常にElementです。
(もう少し広くコンポーネント指向のコンポーネントを定義すると、それは、上記のような関数を含めるすべてのファーストクラスオブジェクトであり、たとえば、
[0,1,2,3]というファーストクラスなも、
[0,1,2,3]という出力を常に返すコンポーネントであると見做すことができます。)
ReactのComponentは、<HelloComponent/>というように、
タグ表記で囲むことで、「インスタンス化」され、Elementとなるわけで、このようなElementを関数型プログラミングの最小単位としての関数と同様に、合成していきます。
そして、その合成の仕方とは、HTMLのタグで文書構造を構築するのとまったく同じ方法で宣言していきます。
Reactの目的はUIの構築ですが、HTMLの作法で、エレメントの物理的上下関係の構造をつくることで、そのままUIの部品の物理的関係の合成、構築となり、この作業を入れ子構造的に繰り返します。
Reactに限らず、コンポーネント指向のコンポーネントは、関数なので、外部の環境に命令すること、副作用は起こしてはいけません。
ReactのコンポーネントであるElementは、自律的に完結しており、外部からの入力を受けて、適切な別のElementを返す、という多重構造になっています。
そのための関数的な機構と、時間変化に対応するFRPとしての機構の2種類がありますが、後述、詳述します。

ReactのElement(エレメント)は、オブジェクトのインスタンスではない、物理的なDOMではなく、論理的な仮想DOM

ReactのComponentは、タグ表記で囲むことで、「インスタンス化」され、Elementとなりますが、これは、HTMLのエレメントと同じように、論理的構造を構築している論理的存在に過ぎず、明確にメモリを確保して物質的存在として振る舞う、オブジェクト指向のオブジェクトのインスタンスではありません。
このようなReactのElement(エレメント)のような存在を特に、VirtualDOM(仮想DOM)と呼びます。
もともと、DOM(DocumentObjectModel)とは、純粋に論理的存在であったHTMLタグ要素を、オブジェクトとして操作するためにオブジェクト指向で設計されたAPIですが、その単位であるオブジェクトを仮想化して、再び論理化した、VirtualDOM(仮想DOM)が、ReactのElementである、ということです。
Reactの内部設計として、VirtualDOM(仮想DOM)の計算結果から、実際にUIの更新操作に必要となる差分だけがDOM操作されることになります。プログラマは直接DOM操作することはありません。
もう少しフェアに言うと、React JSXコードの最後の、
唯一の、document.bodyあるいはその他のHTMLドキュメント部分に唯一ReactのElementをマウントする宣言部分のみが、リアルDOMと接触する箇所です。

もう一度、静的なドキュメントをHTMLからReact JSXに移行、最初の一歩

以上の理解を踏まえながら、もう一度、

HTML

単純なHTMLコード
classic00.html
<div>Hello</div>
表示結果

Hello
— をJSXに移行させます。

React JSX

react00-1.html ←JSXを起動する枠組みだけ
<!-- The core React library -->
<script src="http://fb.me/react-0.12.1.js"></script>
<!-- In-browser JSX transformer, remove when pre-compiling JSX. -->
<script src="http://fb.me/JSXTransformer-0.12.1.js"></script>

<script type="text/jsx" src="react00-1.js"></script>
react00-1.js ←JSX
var HelloComponent = React.createClass(
{
  render: function()
  {
    var el = (<div>Hello</div>);
    return el;
  }
});

var HelloComponentEL = <HelloComponent/>;
var mount = React.render(HelloComponentEL, document.body);
HelloComponentはReactのComponentなので、
必ず、ReactのElementを返すわけですが、
その、Elementは、
var el = (<div>Hello</div>);で定義しています。

鶏が先か?卵が先か?ElementComponentか?一番最初のパーツは何か

<div>というのは、
これは見ての通り、既存のHTMLでお馴染みのタグです。
既存のHTMLでお馴染みのタグ、のように見えますが、
実際は、すでに説明したとおり、これも、
ReactのVirtualDOM(仮想DOM)であり、
ReactのElementなので、
もともとは、ReactのComponentで、
HelloComponentと同じようにどこかで設計されていたはずだ、と考えてしまいます。

ReactのElementとは、Componentによって設計されて、
Componentをタグ表記で「インスタンス化」したものが、
Elementになっています。

Componentを設計する際には、必ず、Elementを返します。
そのElementは、必ずもともとは、どこかで設計されたComponentで、
と鶏が先か?卵が先か?の延々多重構造になっていることに気がつくことでしょう。
じゃあ、そもそもの一番最初の鶏か卵か、
ElementComponentか、
それは一体何だったのでしょうか??

ネイティブなReactのComponent(コンポーネント)

実は、<div>というElementは、どこかで、
var div = React.createClass(
{
  render: function()
  {
    var el = (????????????);
    return el;
  }
});
などと、わざわざ定義をする必要がない
ネイティブなReactのComponent(コンポーネント)です。
このdivのような、ネイティブなReactのComponent(コンポーネント)を起点として、ユーザはオリジナルなコンポーネントを設計して、いわば、カスタマイズされたHTMLタグ=Elementを「インスタンス化」して、HTML構造と同じような表記でコンポーネントを合成していくわけです。
実際、このような、ネイティブなReactのComponentと、ユーザが定義するComponentは、Reactでは厳密に区別されており、その印として、
ネイティブ・コンポーネントの名前は、頭文字は小文字、
オリジナル・コンポーネントの名前は、頭文字は大文字、
という独特の表記ルールがあります。この表記ルールを守らなければReactは適切に動作しません。
https://facebook.github.io/react/docs/jsx-in-depth.html#html-tags-vs.-react-components

もう少しだけ複雑な、静的なドキュメントをHTMLからReact JSXに移行


classic01.html


<div>
  Hello
  <div>child</div>
  <div>child</div>
  <div>child</div>
</div>
Hello
child
child
child

という、もう少しだけ複雑な、静的なドキュメントをHTMLからReact JSXに移行させることを試みます。
単純に、
  var HelloComponent = React.createClass(
  {
    render: function()
    {
      var el = (
        <div>
          Hello
          <div>child</div>
          <div>child</div>
          <div>child</div>
        </div>
      );
      return el;
    }
  });

  var mount = React.render(<HelloComponent/>, document.body);
というように、HelloComponentが返すElementである、
elの値を上記HTMLにしてやれば、いとも簡単に移行できます。
しかし、いざ、ReactのElementがファーストクラスであり、
自由自在に取り扱えると理解してしまった、少なくともその可能性を感じることができる今となっては、
<div>child</div>を何度も繰り返す冗長性が気になるはずです。
<div>child</div>は別のコンポーネントとして切り出して、別途定義してやったほうが、上のコードの冗長性は排除できるし、今後自由度が上がり、出来ることも柔軟に増えてくるはずです。

ChildComponentを定義して、コンポーネントを自由に組み合わせる

そこで、
<div>child</div>は、
ChildComponentとして、
別途切り出して定義しなおします。
定義した
ChildComponentというComponentを、
「インスタンス化」してやると
<ChildComponent/>というElementとなるので、
<ChildComponent/>= <div>child</div>
である、ということです。
実際は、上記のように、
ElementElement
というような定義の表記は出来ないので、
整合的に、まず
ChildComponentというComponentを定義してやり、
そこから、改めて、
<ChildComponent/>というElement
「インスタンス化」してやる、という作法です。
結果的に、
<ChildComponent/>= <div>child</div>
となるような、
ChildComponentというComponentを定義する方法は、
もちろん、
var ChildComponent = React.createClass(
{
  render: function()
  {
    var el = (<div>child</div>);
    return el;
  }
});
であり、結果的に、
<ChildComponent/>= <div>child</div>となるのだから、
HelloComponentの定義は以下のようになり、冗長性が排除されました。
var HelloComponent = React.createClass(
{
  render: function()
  {
    var el = (
      <div>
        Hello
        <ChildComponent/>
        <ChildComponent/>
        <ChildComponent/>
      </div>
    );
    return el;
  }
});
普通に、全体のコードはその2つのコンポーネントの定義を並べた、以下になります。
var HelloComponent = React.createClass(
{
  render: function()
  {
    var el = (
      <div>
        Hello
        <ChildComponent/>
        <ChildComponent/>
        <ChildComponent/>
      </div>
    );
    return el;
  }
});

var ChildComponent = React.createClass(
{
  render: function()
  {
    var el = (<div>child</div>);
    return el;
  }
});

var mount = React.render(<HelloComponent/>, document.body);
これが、Reactでコンポーネントを設計し、エレメントにして組み合わせて、また別のコンポーネントの返り値として設計する、という基本です。ひたすらこういうことを繰り返します。
単純な静的なHTMLコードをJSXに置き換えたのですが、HTMLのElementが、ReactではJavaScript(JSX)のファーストクラスとして扱えることにより、自由度が上がり始めたことがわかるでしょう。

ChildComponentから、ChildrenComponentを定義して、さらにコンポーネントの冗長性を排除することを試みる 


 もう、こうなると、次は、
<ChildComponent/>
<ChildComponent/>
<ChildComponent/>
という、「同じものの繰り返し」が気になってくるわけです。
現行では、3回の繰り返しでなんとかなってはいるが、
もし、これが100回の繰り返しだとどうするんだ?とかですね。
実際に、Webアプリを構築すると、こういうコンポーネント・エレメントが延々と繰り返して登場する、登場させたい設計は普通に出てくるわけです。たとえば、TwitterやFacebookのタイムラインもそうでしょうし、まさにああいうパーツを柔軟なコンポーネントとして定義して上手くやる、というのが、このReactの真骨頂なのです。
3回連なっている冗長な部分、
<ChildComponent/>
<ChildComponent/>
<ChildComponent/>
あるいは、TwitterやFacebookのタイムラインの枠組みとなるUI部分は、
ChildrenComponentとして、
ひとつのコンポーネントにまとめてしまいましょう。
故に、大枠である、
HelloComponentの設計は以下のようになります。
var HelloComponent = React.createClass(
{
  render: function()
  {
    var el = (
      <div>
        Hello
        <ChildrenComponent/>
      </div>
    );
    return el;
  }
});
一番低レベルのコンポーネントである、
ChildComponentは同じ。
var ChildComponent = React.createClass(
{
  render: function()
  {
    var el = (<div>child</div>);
    return el;
  }
});
いよいよ、ChildrenComponentの設計ですが、
var ChildrenComponent = React.createClass(
{
  render: function()
  {
    var elArray = 
     [<ChildComponent/>,
      <ChildComponent/>,
      <ChildComponent/>];

    var el = (<div>{elArray}</div>);
    return el;
  }
});
となります。
ReactのElementはファーストクラスなので、
普通に値として、配列の要素になります。
だから、
 var elArray = 
     [<ChildComponent/>,
      <ChildComponent/>,
      <ChildComponent/>];
というReactのElementの配列が定義できます。
var el = elArray; return el;
と返したくなるのですが、ReactのElementは、必ず一番外側はひとつのエレメントで括られていないいけないと厳密な仕様なので、外側を更に<div></div>でくくる必要があります。
<div>elArray</div>としたいところですが、
これだと、単に、ただの「elArray」という文字列が返ってしまいます。
では、<div><elArray/></div>なのか?
というと、これも違って、
上記の、elArrayの定義は、ReactのComponentとしての定義ではないので、こういう、非ReactComponentを、
ReactのElementとして、仮想DOMとして「インスタンス化」するためには、少なくとも、それらの中に組み込んで同列に表記するためには、{}中括弧で、括ることで明示します。
だから、
var el = (<div>{elArray}</div>);となります。
全部のコードは、
var HelloComponent = React.createClass(
{
  render: function()
  {
    var el = (
      <div>
        Hello
        <ChildrenComponent/>
      </div>
    );
    return el;
  }
});

var ChildrenComponent = React.createClass(
{
  render: function()
  {
    var elArray = 
     [<ChildComponent/>,
      <ChildComponent/>,
      <ChildComponent/>];

    var el = (<div>{elArray}</div>);
    return el;
  }
});

var ChildComponent = React.createClass(
{
  render: function()
  {
    var el = (<div>child</div>);
    return el;
  }
});

var mount = React.render(<HelloComponent/>, document.body);
となり、想定通りの表示となりますが、
ChildrenComponentの設計のElementの配列は、繰り返しの冗長さがそのまま残っているわけで、まだ改善しなければいけません。

Componentの関数特性としてのInputとOutput

ChildrenComponentの設計は、もうひとつ道具を揃えてから、あとでまとめてしっかり続きをやるとして、先に、そのもうひとつの道具立てをします。
ReactのComponentは、関数であり、Inputを受け取り、それに呼応したOutputを返します。
返り値は常にElementです。
このComponentの関数特性により、たとえば、前述の、TwitterやFacebookのタイムラインの枠組みとなるUI部分を設計するにしても、あるComponentに適切なInputを入力してやると、それに呼応したUI表示が得られる、というような堅牢な設計が関数型プログラミング、宣言型のコードで可能になります。
このReactのComponentの関数のInputを司るのが、
this.propです。
いわゆるHTMLタグのproperty属性をプログラマが自由に定義して、Inputし、Component内で、関数の引数のように受け取って値を取り回すための機構です。
たとえば、
<div>
  Hello
  <div>child0</div>
  <div>child1</div>
  <div>child2</div>
</div>
Hello
child0
child1
child2

こういう、HTMLコードをReact JSXで、HTML同様に宣言的に、かつ関数型プログラミング的にコンポーネント指向で柔軟に表現したいとします。非常にありがちで典型的なケースでしょう。
さっそく、その具体的コードを見ましょう。
var HelloComponent = React.createClass(
{
  render: function()
  {
    var el = (
      <div>
        Hello
        <ChildComponent input={0}/>
        <ChildComponent input={1}/>
        <ChildComponent input={2}/>
      </div>
    );
    return el;
  }
});

var ChildComponent = React.createClass(
{
  render: function()
  {
    var el = (<div>child{this.props.input}</div>);
    return el;
  }
});

var mount = React.render(<HelloComponent/>, document.body);
前述の{}中括弧が、活躍しています。
JavaScript(JSX)内の値を、ReactのElement領域に変換して受け渡す糊みたいな役割を果たす表記が、この{}中括弧です。
<div>child0</div>
<div>child1</div>
<div>child2</div>
というのは、冗長なので、
ChildComponent化したやつですが、
今回はさらに、0,1,2と、さらにカスタマイズして表示できるように、コンポーネント化しなければいけません。
そこで、前回のコードをさらに推し進めて、
  <ChildComponent input={0}/>
  <ChildComponent input={1}/>
  <ChildComponent input={2}/>
という風にします。これで、inputというReactのElementpropertyに、それぞれ、012という値が受け渡され、ChildComponentというコンポーネント、あるいは関数の引数となります。
ChildComponentの返り値としてのElementelでは、
var el = (<div>child{this.props.input}</div>);
と、`this.props.input`で、引数が受け取れ、 `{}`中括弧でもちろん変換して`Element`に組み込みます。

ChildrenComponentのElement配列とComponentの関数特性の合わせ技

<div>
  Hello
  <div>child0</div>
  <div>child1</div>
  <div>child2</div>
  <div>child3</div>
  <div>child4</div>
  <div>child5</div>
  <div>child6</div>
  <div>child7</div>
  <div>child8</div>
  <div>child9</div>
</div>
Hello
child0
child1
child2
child3
child4
child5
child6
child7
child8
child9

というように、10個に増やしてみました。
しかも、同じように、カスタマイズ表示が必要です。
いよいよ、まさに、TwitterやFacebookのタイムラインなど、ああいうパーツを柔軟なコンポーネントとして定義して上手くやるReactの真価が発揮できる局面であり、これまでの、HTML+JavaScriptではだんだん実装するのが、しんどくなってくる領域であり、パフォーマンスチューニングの懸念も出てくるような局面です。仮想DOMでリアルDOMには差分でしか描写しないReactはその辺の煩わしさも一切ありません。あくまで論理的に、関数型プログラミングの領域で宣言的に淡々と進行させます。
まず、また冗長性を排除しながらカスタマイズが必要なUI領域を
ChildrenComponentとしてコンポーネントにまとめなおし、その上で、一番外側の最上位のHelloComponentを設計します。
var HelloComponent = React.createClass(
{
  render: function()
  {
    var el = (
      <div>
        Hello
        <ChildrenComponent/>
      </div>
    );
    return el;
  }
});
そして、もっとも低階層のChildComponentは、さっきのコンポーネントとまったく同じです。
var ChildComponent = React.createClass(
{
  render: function()
  {
    var el = (<div>child{this.props.input}</div>);
    return el;
  }
});
そして、ChildrenComponentの設計です。
var ChildrenComponent = React.createClass(
{
  render: function()
  {
    var createChild = function(n)
    {
      return (<ChildComponent input={n}/>);
    };

    var elArray = [0,1,2,3,4,5,6,7,8,9].map(createChild);

    var el = (<div>{elArray}</div>);
    return el;
  }
});
コンポーネント内部に、
var createChild = function(n)
    {
      return (<ChildComponent input={n}/>);
    };
という、ChildComponentElementを引数nに応じて、自動生成する関数を設計して用意します。
0-9の配列、[0,1,2,3,4,5,6,7,8,9]を用意します。
それに、関数型プログラミング的に、
createChild関数をmapしてやります。
var elArray = [0,1,2,3,4,5,6,7,8,9].map(createChild);
この結果、map高階関数の返り値であるelArrayには、
elArray = 
     [<ChildComponent input={0}/>,
      <ChildComponent input={1}/>,
      <ChildComponent input={2}/>,
      <ChildComponent input={3}/>,
      <ChildComponent input={4}/>,
      <ChildComponent input={5}/>,
      <ChildComponent input={6}/>,
      <ChildComponent input={7}/>,
      <ChildComponent input={8}/>,
      <ChildComponent input={9}/>];
という値が格納されることになります。論理的に。
そして、
var el = (<div>{elArray}</div>);
というChildrenComponentの返り値となるので、
想定した通りの結果が表示されます。
もちろん、関数型プログラミングなので、
繰り返しのフロー、命令形のコードを書くことはありません。
React JSXで、統合的に宣言型コーディングすると何故良くなるのか?というのは、何故、関数型プログラミングが良いのか?というのとまったく同じ事を語ることであり、まったく同じ理由なので、その辺りは延々と本稿の冒頭で引用している記事やその延長の著書で解説しているのでそちらを参照してください。

Facebook-Immutable を使ってさらに関数型プログラミングでReactする

もちろん、
0-9の配列、[0,1,2,3,4,5,6,7,8,9]を用意する、というのは、言うまでもなくスマートなアプローチではないですから、ここも関数型プログラミングにします。
HTMLコードに、
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.6.4/immutable.min.js"></script>
とポインタを追加することで、著書でも解説している、
Facebookのもうひとつの関数ライブラリ、
Facebook-Immutable
が活用できるようになります。
配列、[0,1,2,3,4,5,6,7,8,9]を用意したければ、
 var array = Immutable.Range(0, 9).toArray();
とすれば、良いので、
 var elArray = array.map(createChild);
となります。 全部のコードは、
var HelloComponent = React.createClass(
{
  render: function()
  {
    var el = (
      <div>
        Hello
        <ChildrenComponent/>
      </div>
    );
    return el;
  }
});

var ChildrenComponent = React.createClass(
{
  render: function()
  {
    var createChild = function(n)
    {
      return (<ChildComponent input={n}/>);
    };

    var array = Immutable.Range(0, 10).toArray();
    var elArray = array.map(createChild);

    var el = (<div>{elArray}</div>);
    return el;
  }
});

var ChildComponent = React.createClass(
{
  render: function()
  {
    var el = (<div>child{this.props.input}</div>);
    return el;
  }
});

var mount = React.render(<HelloComponent/>, document.body);
となります。 念の為ですが、結果は、想定したとおり、
Hello
child0
child1
child2
child3
child4
child5
child6
child7
child8
child9

となります。
以上で、
FRPを必要としない静的なドキュメントを、
HTMLからJSXへ移行させる基礎固めは終了です。
おそらく、この解説で、時間変化を取り扱わない静的なHTMLページをReact JSXに移行することはだいたい出来るはずです。もちろん既存のテンプレートエンジン、プラグインなどをふんだんに利用しているページをなんでも移行できるという意味ではなく、スキルとして静的なHTMLページをより見通しよく冗長性を排除しながら再構築できるはずである、ということです。
時間変化を取り扱う動的なWebアプリケーションをReactで実現するためには、改めてFRPをReactでどのように具現化するか、より注意深く考察しながら取り組む必要があり、それは続く記事で執筆して公開します。

0 コメント:

コメントを投稿

Popular Posts