で、内容の流れ、紙面、諸々の都合で書ききれなかった、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コードの構造は単純明快です。
進化したWebのHTML+JavaScript 【命令形コード】
Webはあっという間に世界中に普及して、静的なWebページ=文書
↓
動的なWebアプリケーション=ユーザ・インタフェース
へと進化しました。
土台となる、静的で宣言型である、
コードの各要素(エレメント)を、オブジェクト指向のオブジェクトとして扱い、JavaScriptで動的に操作するという命令形プログラミングになりました。
さらに進化した次世代WebのReact JSX(HTML+JavaScript) 【宣言型コード】
動的なWebアプリケーション=ユーザ・インタフェースは、洗練され複雑化していきました。Facebookは肥大化、複雑化する自サイトを再構築するために、新たな技術Reactを開発します。
Reactは関数型プログラミングの潮流にあり、コンポーネント指向の宣言型コードでWebアプリケーションを構築します。
かつては、HTMLで宣言的に記述して、JavaScriptで動的に操作していた、分断されていた構造は、Reactでは、JavaScriptを拡張したJSX言語で統合的に宣言型コーディングします。
HTMLはWebの既存のプロトコルとして、JSXを起動する枠組みだけが残ります。
この図のように、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>
表示結果を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 ←JSXvar HelloComponent = React.createClass(
{
render: function()
{
return (<div>Hello</div>);
}
});
var mount = React.render(<HelloComponent/>, document.body);
表示結果ファイル名を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>
表示結果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 ←JSXvar 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>);
で定義しています。
鶏が先か?卵が先か?Element
かComponent
か?一番最初のパーツは何か
<div>
というのは、 これは見ての通り、既存のHTMLでお馴染みのタグです。
既存のHTMLでお馴染みのタグ、のように見えますが、
実際は、すでに説明したとおり、これも、
Reactの
VirtualDOM
(仮想DOM)であり、 Reactの
Element
なので、 もともとは、Reactの
Component
で、 HelloComponent
と同じようにどこかで設計されていたはずだ、と考えてしまいます。Reactの
Element
とは、Component
によって設計されて、 Component
をタグ表記で「インスタンス化」したものが、 Element
になっています。Component
を設計する際には、必ず、Elementを返します。そのElementは、必ずもともとは、どこかで設計されたComponentで、
と鶏が先か?卵が先か?の延々多重構造になっていることに気がつくことでしょう。
じゃあ、そもそもの一番最初の鶏か卵か、
Element
かComponent
か、 それは一体何だったのでしょうか??
ネイティブな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>
という、もう少しだけ複雑な、静的なドキュメントを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>
である、ということです。
実際は、上記のように、
Element
=Element
というような定義の表記は出来ないので、
整合的に、まず
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>
こういう、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のElement
のproperty
に、それぞれ、0
、1
、2
という値が受け渡され、ChildComponent
というコンポーネント、あるいは関数の引数となります。ChildComponent
の返り値としてのElement
のel
では、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>
というように、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}/>);
};
という、ChildComponent
のElement
を引数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);
となります。
念の為ですが、結果は、想定したとおり、
となります。
以上で、
FRPを必要としない静的なドキュメントを、
HTMLからJSXへ移行させる基礎固めは終了です。
おそらく、この解説で、時間変化を取り扱わない静的なHTMLページをReact JSXに移行することはだいたい出来るはずです。もちろん既存のテンプレートエンジン、プラグインなどをふんだんに利用しているページをなんでも移行できるという意味ではなく、スキルとして静的なHTMLページをより見通しよく冗長性を排除しながら再構築できるはずである、ということです。
時間変化を取り扱う動的なWebアプリケーションをReactで実現するためには、改めてFRPをReactでどのように具現化するか、より注意深く考察しながら取り組む必要があり、それは続く記事で執筆して公開します。
0 コメント:
コメントを投稿