Skip to content

Instantly share code, notes, and snippets.

@ken-okabe
Last active November 26, 2019 05:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ken-okabe/d1ff6e85cf2b2327f6c6 to your computer and use it in GitHub Desktop.
Save ken-okabe/d1ff6e85cf2b2327f6c6 to your computer and use it in GitHub Desktop.
Hello!
#React 入門 2016 あるいは statelessさらにprop不要で関数型・宣言型的にコーディングする手法
#React(0.14+), JavaScript(ES6)は変化が激しすぎるのでReact入門記事を全面改訂します
当ブログで昨年2015年4月にUPしたReact解説記事(2つ)
- [React (.js Facebook)解説 関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間 サポート記事 静的HTML編](http://kenokabe-techwriting.blogspot.jp/2015/04/react-js-facebook-iq145-html.html)
- [React 解説【動的HTML-FRP編】](http://kenokabe-techwriting.blogspot.jp/2015/05/react-html-frp.html)
が時代遅れになりすぎて(使いものにならなくなって)いるので、年始に全面改訂して公開します
今回、上記2つのReact入門・解説記事を一本の記事へ焼き直し、統合し、上書きするように全面改訂しますが、其の前に以下しばらく、そこに至る情勢分析と前提のようなものを記します。
JavaScript(ES6)やBabelトランスパイラも含めて、前回の記事を参照。
[2016年のnode、ES6、React、Babel、Atomエディタ界隈の方向性](http://kenokabe-techwriting.blogspot.jp/2015/12/2016nodees6reactbabelatom.html)
#現在のReactバージョンは0.14.5
#[React v0.14 major changes](https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html)
- Two Packages: React and React DOM
ReactからReactDOMが分離された。
理由はもちろん、DOMのWebブラウザのみならず、iOS,Androidが稼働するスマートフォンのモバイルアプリでもReactで統一的にコーディングするため。
共通の基盤となるReactと、Webブラウザ用ReactDOM、モバイルアプリ用のReactNative。
>**This paves the way to writing components that can be shared between the web version of React and React Native.** We don’t expect all the code in an app to be shared, but we want to be able to share the components that do behave the same across platforms.
Webブラウザ用には、以下のように、
`react`に加え、分離された`react-dom`の2つが必要。
また、DOMにマウントして接続するコードは`ReactDOM.render`と変更された。
```
var React = require('react');
var ReactDOM = require('react-dom');
var HelloComponent = () => (<div>HelloComponent!!</div>);
var mount = ReactDOM.render(HelloElement, document.getElementById('container'));
```
- Deprecation of react-tools
Reactツールの廃止
>The react-tools package and JSXTransformer.js browser file have been deprecated. You can continue using version 0.13.3 of both, but we no longer support them and recommend migrating to Babel, which has built-in support for React and JSX.
などについては、
[JavaScriptではES6+とReact-JSXからES5へのトランスパイルが標準に / ATOMエディタで最速環境構築 厳選パッケージ 3 + 3 2015年夏バージョン](http://kenokabe-techwriting.blogspot.jp/2015/08/javascriptes6react-jsxes5-atom-3-32015.html)と
[上述の前回記事](http://kenokabe-techwriting.blogspot.jp/2015/12/2016nodees6reactbabelatom.html)を参照のこと。
#Stateless functional components / Statelessな関数型コンポーネント
###[React v0.14 major changes#stateless-functional-components](http://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#stateless-functional-components)
>In idiomatic React code, most of the components you write will be stateless, simply composing other components. We’re introducing a new, simpler syntax for these components where you can take props as an argument and return the element you want to render:
>*Reactコードの特徴として、あなたが書くほとんどのコンポーネントはstatelessで、単純に他のコンポーネントをコンポーズしていきます。引数としてpropsをとることができ、レンダーしたいelementを返したい、こういうコンポーネントのための、新しい、よりシンプルなシンタックスを紹介します。*
>This pattern is designed to encourage the creation of these simple components that should comprise large portions of your apps. In the future, we’ll also be able to make performance optimizations specific to these components by avoiding unnecessary checks and memory allocations.
>*あなたのアプリの大部分を構成するだろう、これらのシンプルなコンポーネントを作成することを推奨すべく、このパターンは設計されています。将来的には、不要なチェック、メモリ割り当てを避けることによってこれらのコンポーネント特有のパフォーマンスの最適化も可能です。*
前回の解説で導入したように、
```
var HelloComponent = React.createClass(
{
render: function()
{
return (<div>Hello</div>);
}
});
```
だったものが、ES6の関数アロー表記による簡略化も伴い、簡潔にこう書けるようになった。
```
var HelloComponent = () => (<div>HelloComponent!!</div>);
```
Reactコンポーネントは、引数をとり、エレメントを返すだけの副作用のない純粋な関数として書けるようになった。
これは非常に重要で大きな変化である。
> **Functional components do not have lifecycle methods**, but you can set .propTypes and .defaultProps as properties on the function.
Stateless functional componentsは其の名のとおりStatelessであり状態を保有しない。引数をとり、エレメントを返すだけの副作用のない純粋な関数である。
旧来からのReact.createClassによって作成されたComponentは、名が体を表すように、オブジェクト指向のクラスとして設計が可能で、状態を保有できる。
#関数型プログラミングのアプローチとしては、Stateless functional components / Statelessな関数型コンポーネントが最良
であるのことは言うまでもない。
Reactは関数型、コンポーネント指向であったにも関わらず、これまでどうにもこうにも書きにくい、煩雑であったのは、今回導入されたStateless functional componentsのように、純粋な関数としてコンポーネントが定義できなかったことにあると考える。
状態をもつことを大前提に設計されているオブジェクト指向と、状態をもたない変換器の集合体としての関数型プログラミングは明確に対立する概念である。
玉虫色に両者を併存させて相互のメリットを、、、という感じで相反概念を頑なに認めようとしないプログラマがなぜか多いが、そういう誤魔化しは時間の問題であり、Reactの今回のMajorChange、Stateless functional components / Statelessな関数型コンポーネントの導入という「進化の方向性」は明確だと思う。
###FAQ オブジェクト指向と関数型は対立していますか?
という興味深い記事で「いいえ」と断言しているので、どんなものかと読み進めてみると、文章の最後には
[上の記述はあくまで理論の話です。紹介記事の冒頭に書いたとおり、「単純な関数型言語に、複雑なオブジェクト指向はいらない」という考え方もあります(私個人の好みもそれに近く、OCamlのOはほとんど使っていません。参考リンク:「オブジェクトは OCaml の鬼子」)。](http://qiita.com/esumii/items/ec589d138e72e22ea97e#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%A8%E9%96%A2%E6%95%B0%E5%9E%8B%E3%81%AF%E5%AF%BE%E7%AB%8B%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%81%8B)のような、言い逃れのような玉虫色のわけのわからない事でお茶を濁されてしまい、馬鹿をみるのは、真面目に読んで混乱して終わった学習者だけなので、こういう説明は止めてもらいたい。
そもそも、「上の記述はあくまで理論の話です」というオチのようだが、「オブジェクト指向」というのは、そもそも「理論」ではない。文字通り「指向」、パラダイムであって、理論ではない。 こんなものは、どこでも書かれている初歩的な知識。
「直交・独立な概念」。文中にある、このFPvsOPの議論のそこら中で大変重宝されているようにみえる常套句であるが、非常に「トリッキーな概念」であるので要注意。というか、はっきり言うと単なる我田引水の「誤魔化し」である。なぜならば、あらゆる概念において、どの角度で切って分析するか?によって、常に「直交・独立な概念」を切り出すことが可能であるから。
[要するに、オブジェクトの状態を破壊的に更新するか(命令型)、新しい状態を持つオブジェクトを作り直して返すか(関数型)というだけの違いです]((http://qiita.com/esumii/items/ec589d138e72e22ea97e#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%A8%E9%96%A2%E6%95%B0%E5%9E%8B%E3%81%AF%E5%AF%BE%E7%AB%8B%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%81%8B))
「だけの違い」でなく、理論ではない指向、パラダイムとしてのオブジェクト指向にとってそこは大きな違いであり、その断面で分析すると「直交・独立な概念」ではありえない、と言うことだって簡単にできる。パラダイム、指向の対比において、「直交・独立な概念」などと相手が言い出したときは、其の人は単に論理的思考能力に劣るか、なんらかの誘導したい帰結に無自覚、其の両方か疑うべきであろう。
理論ではなく、パラダイム、指向の話で、他のパラダイムとの際をひたすら有耶無耶にっすることに努め、玉虫色を強調するほど愚かなことはない。
なぜこういうことが起こるのか?というと、そもそも、FPvsOPというのはよく知られた対立軸であり、周囲に波風を起こしたくない(特に和を尊しとする我々日本人には顕著)、穏当に、というバイアスと、論者の「保身」がある。割を食うのは常に真面目に勉強したいと思う学習者である。小中高、あるいは大学でそのような曖昧な説明しかしない愚かな教師にあたって迷惑を被った人も多いだろう。
# Answer: オブジェクト指向と関数型プログラミングは、「状態の有無」という要点で明確に対立する
そもそも、Reactというのは、HTML、Webプログラミングを支配してきたDOM(オブジェクト指向)から、関数型プログラミングへの脱却。
Reactコンポーネントは、根本的に、純粋な関数として設計されるべきであるし、State、状態がある仕様は間違っていると考える。
#では、Reactコンポーネントには、なぜState、状態がある仕様であり続けていたのか?
State、状態の取り扱いがプログラミングには必要不可欠である、と大多数のプログラマが考えており、適切な解法を見いだせておらず、いわば「必要悪」として実装せざるを得ないから。
State、状態がないほうがシンプル、簡潔なコードになる、ということ自体は特に関数型プログラミングに精通している人を中心に多くのプログラマが理解しており、上記のようなFacebookブログの言葉の端々にもそれは確認できる。
#Stateless functional components / Statelessな関数型コンポーネントのみを利用するStatelessなReactプログラミングの実現を目指す
これを実現、実証するのがこの「入門記事」なので、Reactプログラミングについて「オーソドックス」なものだけを期待している方はこの記事の対象読者ではありません。
以下、
[React (.js Facebook)解説 関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間 サポート記事 静的HTML編](http://kenokabe-techwriting.blogspot.jp/2015/04/react-js-facebook-iq145-html.html)
[React 解説【動的HTML-FRP編】](http://kenokabe-techwriting.blogspot.jp/2015/05/react-html-frp.html)
の内容を、一部そのまま踏襲し、焼き直しながら、議論を拡張します。
[関数型プログラミングに目覚めた! IQ145の女子高生の先輩から受けた特訓5日間](http://www.amazon.co.jp/gp/product/4798043761/ref=as_li_ss_tl?ie=UTF8&camp=247&creative=7399&creativeASIN=4798043761&linkCode=as2&tag=tedlearner-22)
で、内容の流れ、紙面、諸々の都合で書ききれなかった、React (.js Facebook)の補足解説で、本書の読者のためのサポート記事です。
著書では、前章からの流れを受けて、関数型プログラミングの考え方とReact公式ページによる導入を踏まえてReactを解説していますが、この記事はその延長かつ、別方向からの切り口での補足解説記事という位置づけです。
広い読者に向けて、この記事単独でもReactに入門できるように(なるだけ)書きます。
![](http://ecx.images-amazon.com/images/I/51mAhARY0RL.jpg)
#原始のWebのHTML 【宣言型コード】
###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のコードはこのように<タグ>の入れ子構造、ツリー構造になっています。
上記のHTMLコードをブラウザで表示(実行)すると、以下のような結果になります。
-----
<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>
-----
HTMLは、
>文書構造を定義する
宣言型コードであり、タグの入れ子構造と上下関係で、文書が定義されます。
あくまでWebページ=文書という静的な対象を定義するためのコードで、HTMLコードの上下関係→文書の上下関係と物理的に対応しています。HTMLコードの構造は単純明快です。
![enter image description here](http://kentutorialbook.github.io/img/fp2/HTML.svg)
#進化したWebのHTML+JavaScript 【命令形コード】
Webはあっという間に世界中に普及して、
静的なWebページ=文書
動的なWebアプリケーション=ユーザ・インタフェース
へと進化しました。
土台となる、静的で宣言型である、
コードの各要素(エレメント)を、オブジェクト指向のオブジェクトとして扱い、JavaScriptで動的に操作するという命令形プログラミングになりました。
![enter image description here](http://kentutorialbook.github.io/img/fp2/HTML-JavaScript.svg)
このように、HTMLのツリー構造の要素を、操作する側のJavaScriptコードから眺めた、操作対象としての「オブジェクト」の総体、仕組みのことを、**DOM(Document Object Model)**と呼びます。DOMはオブジェクト指向の潮流から誕生しました。
http://www.w3.org/TR/DOM-Level-2-Core/introduction.html
>The name "Document Object Model" was chosen because it is an "object model" in the traditional **object oriented** design sense: documents are modeled using objects, and the model encompasses not only the structure of a document, but also the behavior of a document and the objects of which it is composed. In other words, the nodes in the above diagram do not represent a data structure, they represent objects, which have functions and identity. As an object model, the DOM identifies:
>The structure of SGML documents has traditionally been represented by an abstract data model, not by an object model. In an abstract data model, the model is centered around the data.
>**In object oriented programming languages, the data itself is encapsulated in objects that hide the data, protecting it from direct external manipulation. ** The functions associated with these objects determine how the objects may be manipulated, and they are part of the object model.
DOMという名前はオブジェクト指向のオブジェクトモデルから命名されたこと、
もともと抽象的なデータモデルでは、データ中心であった。
オブジェクト指向プログラミング言語では、データそのものは、オブジェクトの中にカプセル化されデータは隠蔽され外部の直接操作から保護され、オブジェクトに紐付けられた関数がそのオブジェクトをどう操作するを決定づける、オブジェクトモデルである、というようなことが書かれています。
要するに、オブジェクト指向とは「状態」を持ち、それを相互に外部から操作していく方法だ、とここでも言及されています。
#さらに進化した次世代WebのReact JSX(HTML+JavaScript) 【宣言型コード】
動的なWebアプリケーション=ユーザ・インタフェースは、洗練され複雑化していきました。
Facebookは肥大化、複雑化する自サイトを再構築するために、新たな技術Reactを開発します。
Reactは関数型プログラミングの潮流にあり、コンポーネント指向の宣言型コードでWebアプリケーションを構築します。
かつては、HTMLで宣言的に記述して、JavaScriptで動的に操作していた、分断されていた構造は、Reactでは、JavaScriptを拡張したJSX言語で統合的に宣言型コーディングします。
HTMLはWebの既存のプロトコルとして、JSXを起動する枠組みだけが残ります。
![enter image description here](http://kentutorialbook.github.io/img/fp2/JSX.svg)
実際に今回この記事を書くにあたり用意したHTMLはこんな感じです。
https://github.com/kenokabe/stateless-react/blob/master/index.html
```HTML
<div id="container"/>
<script src="index.js"></script>
```
もちろん、HTML5の要件には満たないし、プロダクションコードにするには、もうちょっと付け加えたほうが良いでしょうが、ReactのHTMLサンプルコードとしての骨格はこれだけで必要十分です。
このHTMLコードの
`<div id="container"/>`
がReactコードとの唯一の接点で、この一点にページ全体がすべて描画されます。
`<script src="index.js"></script>`
というのは、もちろんReactのJSXコードを起動するポイントです。
この図のように、React JSXで、統合的に宣言型コーディングすると何故良くなるのか?というのは、何故、関数型プログラミングが良いのか?というのとまったく同じ事を語ることであり、まったく同じ理由なので、その辺りは延々と[著書の立ち読み](http://kenokabe-techwriting.blogspot.jp/2015/04/iq145.html)やその延長の[著書](http://www.amazon.co.jp/gp/product/4798043761/ref=as_li_ss_tl?ie=UTF8&camp=247&creative=7399&creativeASIN=4798043761&linkCode=as2&tag=tedlearner-22)で解説しているのでそちらを参照してください。
動的なWebアプリケーション=ユーザ・インタフェースを、静的な宣言型コードで書くために必要なのは、関数型プログラミングの潮流にある関数型リアクティブプログラミング(FRP)の手法です。
ReactはFRPの機能が実装されています。
FRPは著書でも関数型プログラミングの考え方、命令型プログラミングとオブジェクト指向からのパラダイムシフトとして解説していますが、重大な発想の転換が必要です。
Reactを理解するには、
1.HTMLからJSXへの移行
2.JavaScriptからFRPを伴うJSXへの移行
と複数の要素があるのですが、本稿では、まず最初にFRPを必要としない静的なドキュメントを、HTMLからJSXへ移行させる基礎固めに、まず注力し、その後でFRPも含めて解説します。
#静的なドキュメントをHTMLからReact JSXに移行、最初の一歩
まずは、単にReact JSXを起動する枠組みだけのHTMLを用意する、わけですが、通常2通り方法があります。
React公式サイトにもある
https://facebook.github.io/react/docs/getting-started.html
###Using React from npm
というのが、ひと手間ふた手間かかるが、プロダクションコードにもそのまま通用する、パフォーマンスも良いスマートな方法で、今回GitHubにあげたサンプルプロジェクト
https://github.com/kenokabe/stateless-react
ではこの方法を採用しています。
また、
実際に今回この記事を書くにあたり用意したHTMLはこんな感じ
https://github.com/kenokabe/stateless-react/blob/master/index.html
```HTML
<div id="container"/>
<script src="index.js"></script>
```
としたのもこの方法です。
本格的に開発に取り組むときには、通常この路線でいきます。
環境を整えるには、繰り返しですが、こちらへ。
[JavaScriptではES6+とReact-JSXからES5へのトランスパイルが標準に / ATOMエディタで最速環境構築 厳選パッケージ 3 + 3 2015年夏バージョン](http://kenokabe-techwriting.blogspot.jp/2015/08/javascriptes6react-jsxes5-atom-3-32015.html)と
[上述の前回記事](http://kenokabe-techwriting.blogspot.jp/2015/12/2016nodees6reactbabelatom.html)を参照のこと。
###Online Transpile
もう一方は、今回使うFRPサンプルとしてのデモのように、
https://github.com/sakurafunctional/sakurafunctional.github.io/blob/master/demo/react-physics/index.html
```
<meta charset="utf-8" />
<style type="text/css">
body {margin:0 0 0 0;}
</style>
<body>
<div id="container">
Wait for Babel Transpiling jsx ...
</div>
<!-- The core React library -->
<script src="https://fb.me/react-0.14.5.min.js"></script>
<script src="https://fb.me/react-dom-0.14.5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.js"></script>
<script type="text/babel" src="./timeengine.js"></script>
<script type="text/babel" src="./index.jsx"></script>
</body>
```
と、Babelトランスパイラのコードをオンラインで読み込んで、実行時に逐次トランスパイルさせてから実行する方法で、まずまず実験やDEMOでは手軽で便利です。
###JSFiddle
通常の開発時にはエディタが低機能なので向きませんが、小さなコードを扱う、環境構築をすっとばして、とにかく動くDEMOコードを貼り付けてみせるとき、たとえば今回のようなときには、JSFiddleなどが手軽なので、今回はそうします。
####単純なHTMLコード
```HTML
<div>Hello</div>
```
####Webブラウザの表示結果
><div>Hello</div>
をJSXに移行させます。
####JSXコード
https://jsfiddle.net/r4y5kdoq/1/
```js
var HelloComponent = () => (<div>HelloComponent!!</div>);
var mount = ReactDOM.render(HelloComponent(), document.getElementById('container'));
```
####Webブラウザの表示結果
><div>HelloComponent!!</div>
####JSXコード1
```
var HelloComponent = () => (<div>HelloComponent!!</div>);
```
というのがReactのコンポーネントの定義で、JavaScript(ES6)の簡潔な関数です。
返り値は、表示させたいHTML要素そのまま。
このように、ReactのJSXではJavaScriptを拡張して、HTML要素が融合されています。
####JSXコード2
```
var mount = ReactDOM.render(HelloComponent(), document.getElementById('container'));
```
は、このReact JSX世界と
####最初にみたHTMLコード
```HTML
<div id="container"/>
```
を接続するコードです。DOM要素`container`が指定されています。
JSXコード中、唯一明示するHTMLのリアルDOMは、このHTMLとJSXを接続するDOM要素のみです。
#JSXの特別拡張ルール
- <HTMLタグ>がJSの値(ファーストクラス・オブジェクト)として取り回せる。(Elementという)
- JSの値は{}で囲むと、<HTMLタグ>の中身として取り回せる(埋め込める)。
- ここで言う<HTMLタグ>とは、JS上の論理的なものであり、計算、再計算されてDOMとしてレンダリング、再レンダリングされる。(VirtualDOM(仮想DOM)という)
- Elementを返すJS関数により、カスタム・タグ関数がJSで柔軟に設計可能。(Componentという)
- <Component/>とするとElementになる。(というルールだったが、Component
がElementを返すだけの副作用のない純粋な関数になったので、このルールは冗長(余計)で、もう不要だと思う)
- ComponentはJS関数なので入力値を取り、出力値(Element)はそれに呼応する。
- そのカスタム・タグもJSの値として取り回せる。
- つまり、HTMLタグがJSの値として自由自在に組み合わせることができるようになる。
- そして、JSの値は{}で囲むと、<HTMLタグ>の中身として取り回せる(埋め込める)のだから、双方向が実現。この双方向性、HTML要素がJSがボーダレスに融合したことこそがReactのパワーの源泉。
- こういうのをコンポーネント志向と呼ばれ、実際、Reactのカスタムタグ設計の関数のことをComponentと言うが、コンポーネント志向はしょせんバズワードなので要注意。Reactは確かにコンポーネント指向に分類されるが、コンポーネント指向がこうあるべきなので、こうなっているとは観察しにくい。現に現在の仕様になるまで結構迷走しているように見える。
#鶏が先か?卵が先か?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の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
ちなみに、スマートフォンデバイスのReactアプリを構築するための、ReactNativeの場合は、もちろん、iOSやらAndroidやらのネイティブUI部品がこのReactのネイティブなコンポーネントとして定義されることになります。
#もう少しだけ複雑な、静的なドキュメントをHTMLからReact JSXに移行
####JS
```
<div>
Hello
<div>child</div>
<div>child</div>
<div>child</div>
</div>
```
####Webブラウザの表示結果
>Hello
child
child
child
という、もう少しだけ複雑な、静的なドキュメントをHTMLからReact JSXに移行させることを試みます。
単純に、
####JSX
https://jsfiddle.net/r4y5kdoq/3/
```jsx
var HelloChildrenComponent = () => (
<div>
Hello
<div>child</div>
<div>child</div>
<div>child</div>
</div>
);
var mount = ReactDOM.render(HelloChildrenComponent(), document.getElementById('container'));
```
というように、`HelloChildrenComponent`が返す値=`Element`を、上記そのままのHTMLにしてやれば、いとも簡単に移行できます。
しかし、いざ、Reactの`Element`がファーストクラスであり、
自由自在に取り扱えると理解してしまった、少なくともその可能性を感じることができる今となっては、
`<div>child</div>`を何度も繰り返す冗長性が気になるはずです。
`<div>child</div>`は別のコンポーネントとして切り出して、別途定義してやったほうが、上のコードの冗長性は排除できるし、今後自由度が上がり、出来ることも柔軟に増えてくるはずです。
#ChildComponentを定義して、コンポーネントを自由に組み合わせる
そこで、
`<div>child</div>`は、
`ChildComponent`として、
別途切り出して新たなComponentとして定義します。
```jsx
var ChildComponent = () => (
<div>child</div>
);
```
切り出して設計定義した`ChildComponent`は純粋な関数で、
`ChildComponent()`と評価して返り値をとると、それは
`<div>child</div>`というElementになっています。
だからそのまま、
####jsx (間違い)
```jsx
var HelloChildrenComponent2 = () => (
<div>
Hello
ChildComponent()
ChildComponent()
ChildComponent()
</div>
```
となるはずだ!とおもって書いてしまうと失敗作です。
####Webブラウザの表示結果(失敗)
> Hello ChildComponent() ChildComponent() ChildComponent()
`ChildComponent()`というのは、無論JSの値であるわけですが、JSX内に融合されているタグ領域の中に、JSの値を埋め込むには、整合性をとるためのルールがありました。
####JSXの特別拡張ルール
- <HTMLタグ>がJSの値(ファーストクラス・オブジェクト)として取り回せる。(Elementという)
というのは慣れたら直感的なので計算通りでしたが、
- JSの値は{}で囲むと、<HTMLタグ>の中身として取り回せる(埋め込める)。
を忘れてしまいがちです。
`{ChildComponent()}`と{}でラップした上で、<HTMLタグ>の中身に埋め込みます。
####JSX
https://jsfiddle.net/r4y5kdoq/4/
```jsx
var ChildComponent = () => (
<div>child</div>
);
var HelloChildrenComponent2 = () => (
<div>
Hello
{ChildComponent()}
{ChildComponent()}
{ChildComponent()}
</div>
);
var mount = ReactDOM.render(HelloChildrenComponent2(), document.getElementById('container'));
```
####Webブラウザの表示結果(成功)
>Hello
child
child
child
これが、Reactでコンポーネントを設計し、エレメントにして組み合わせて、また別のコンポーネントの返り値として設計する、といういわゆる「コンポーネント指向」としての基本となります。
ひたすらこういうことを繰り返します。
単純な静的なHTMLコードをJSXに置き換えたのですが、HTMLの`Element`が、ReactではJavaScript(JSX)のファーストクラスとして扱えることにより、俄然自由度が上がり始めたことがわかるでしょう。
#ChildComponentから、ChildrenComponentを定義して、さらにコンポーネントの冗長性を排除することを試みる
もう、こうなると、次は、
```jsx
{ChildComponent()}
{ChildComponent()}
{ChildComponent()}
```
という、「同じものの繰り返し」が気になってくるわけです。
現行では、3回の繰り返しでなんとかなってはいるが、
もし、これが100回の繰り返しだとどうするんだ?とかですね。
実際に、Webアプリを構築すると、こういうコンポーネント・エレメントが延々と繰り返して登場する、登場させたい設計は普通に出てくるわけです。たとえば、TwitterやFacebookのタイムラインもそうでしょうし、まさにああいうパーツを柔軟なコンポーネントとして定義して上手くやる、というのが、このReactの真骨頂なのです。
3回連なっている冗長な部分、
```jsx
{ChildComponent()}
{ChildComponent()}
{ChildComponent()}
```
あるいは、TwitterやFacebookのタイムラインの枠組みとなるUI部分は、
`ChildrenComponent`として、
ひとつのコンポーネントにまとめてしまいましょう。
故に、大枠である、
`HelloChildrenComponent3`の設計は以下のようになります。
```jsx
var HelloChildrenComponent3 = () => (
<div>
Hello
{ChildrenComponent()}
</div>
);
```
一番低レベルのコンポーネントである、
`ChildComponent`はこれまでとまったく同じ。
```jsx
var ChildComponent = () => (
<div>child</div>
);
```
いよいよ、`ChildrenComponent`の設計ですが、
Reactの`Element`はファーストクラスなので、
普通に値として、配列の要素になります。
だから、
```
var elArray = [ChildComponent(),
ChildComponent(),
ChildComponent()];
```
というReactの`Element`の配列が定義できます。
`var el = elArray; return el;`
と返したくなるのですが、Reactの`Element`は、必ず一番外側はひとつのエレメントで括られていないいけないと厳密な仕様なので、外側を更に`<div></div>`でくくる必要があります。
そして、
`<div>elArray</div>`としたいところですが、
これだと、単に、ただの「elArray」という文字列が返ってしまう失敗作。忘れがちな、
####JSXの特別拡張ルール
- JSの値は{}で囲むと、<HTMLタグ>の中身として取り回せる(埋め込める)。
がありました。
 
だから、正解は、
`var el = (<div>{elArray}</div>);`
となります。
値は、JSXタグ領域では{}で括らないと、そのままHTML文字列として評価されてしまう。
ChildrenComponentの設計は、
```
var ChildrenComponent = () => {
var elArray = [ChildComponent(),
ChildComponent(),
ChildComponent()];
var el = (<div>{elArray}</div>);
return el;
};
```
となります。
したがって、全部のコードをまとめると、
###jsx
https://jsfiddle.net/r4y5kdoq/5/
```jsx
var ChildComponent = () => (
<div>child</div>
);
var ChildrenComponent = () => {
var elArray = [ChildComponent(),
ChildComponent(),
ChildComponent()];
var el = (<div>{elArray}</div>);
return el;
};
var HelloChildrenComponent3 = () => (
<div>
Hello
{ChildrenComponent()}
</div>
);
var mount = ReactDOM.render(HelloChildrenComponent3(), document.getElementById('container'));
```
となり、想定通りの表示となりますが、
`ChildrenComponent`の設計の`Element`の配列は、繰り返しの冗長さがそのまま残っているわけで、まだ改善しなければいけません。
#Stateless functional components / Statelessな関数型コンポーネントとしてのInputとOutput
`ChildrenComponent`の設計は、もうひとつ道具を揃えてから、あとでまとめてしっかり続きをやるとして、先に、そのもうひとつの道具立てをします。
Reactの`Component`(Stateless functional components)は、関数であり、Inputを受け取り、それに呼応したOutputを返します。
返り値は常に`Element`です。
この`Component`の関数特性により、たとえば、前述の、TwitterやFacebookのタイムラインの枠組みとなるUI部分を設計するにしても、ある`Component`に適切なInputを入力してやると、それに呼応したUI表示が得られる、というような堅牢な設計が関数型プログラミング、宣言型のコードで可能になります。
たとえば、
```html
<div>
Hello
<div>child0</div>
<div>child1</div>
<div>child2</div>
</div>
```
<div>
Hello
<div>child0</div>
<div>child1</div>
<div>child2</div>
</div>
---
このような、HTMLコードをReact JSXで、HTML同様に宣言的に、かつ関数型プログラミング的にコンポーネント指向で柔軟に表現したいとします。非常にありがちで典型的なケースでしょう。
さっそく、その具体的コードを見ましょう。
###jsx
https://jsfiddle.net/r4y5kdoq/6/
```
var ChildNumberComponent = (number) => (
<div>child{number}</div>
);
var ChildrenNumberComponent3 = () => {
var el = (
<div>
{ChildNumberComponent(0)}
{ChildNumberComponent(1)}
{ChildNumberComponent(2)}
</div>
);
return el;
};
var mount = ReactDOM.render(ChildrenNumberComponent3(), document.getElementById('container'));
```
####Webブラウザの表示結果
>child0
child1
child2
注目の`ChildNumberComponent`の設計では、
```
var ChildNumberComponent = (number) => (
<div>child{number}</div>
);
```
前述の`{}`中括弧が、活躍しています。
JavaScript(JSX)内の値を、Reactの`Element`領域に変換して受け渡す糊みたいな役割を果たす表記が、この`{}`中括弧です。
```jsx
<div>child0</div>
<div>child1</div>
<div>child2</div>
```
というのは、冗長なので、
`ChildComponent` にしてしまいましたが、
今回はさらに、0,1,2と、さらにカスタマイズして表示できるように、コンポーネントを設計しなければなりません。
そこで、前回のコードをさらに推し進めて、
```jsx
{ChildNumberComponent(0)}
{ChildNumberComponent(1)}
{ChildNumberComponent(2)}
```
という風にします。これでそれぞれ、`0`、`1`、`2`という値が受け渡され、`ChildNumberComponent`というコンポーネント、あるいは関数の引数として通常のJSの仕様通りシームレスに機能します。
#もう少し「値」として整理して配列にする
###jsx
https://jsfiddle.net/r4y5kdoq/7/
```jsx
var ChildNumberComponent = (number) => (
<div>child{number}</div>
);
var ChildrenNumberComponent5 = () => {
var el = (
<div>
{[ChildNumberComponent(0),
ChildNumberComponent(1),
ChildNumberComponent(2),
ChildNumberComponent(3),
ChildNumberComponent(4)]}
</div>
);
return el;
};
var mount = ReactDOM.render(ChildrenNumberComponent5(), document.getElementById('container'));
```
####Webブラウザの表示結果
>child0
child1
child2
child3
child4
特に説明は不要でしょう。
棚上げにしていた、
`ChildrenComponent`や`ChildrenNumberComponent`の設計の`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>
```
<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はその辺の煩わしさも一切ありません。あくまで論理的に、関数型プログラミングの領域で宣言的に淡々と進行させます。
```jsx
var ChildNumberComponent = (number) => (
<div>child{number}</div>
);
```
はそのまま共通で流用。ここで、問題は
`ChildrenNumberComponent`の設計の`Element`の配列の、繰り返しの冗長さについてなので、
この場合10個分、0-9の配列、`[0,1,2,3,4,5,6,7,8,9]`を用意します。
それに、関数型プログラミング的に、
`ChildNumberComponent`関数を高階関数で`map`してやります。
```
var elArray
= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(ChildNumberComponent);
```
この結果、`map` 高階関数の返り値である`elArray`には、
```jsx
elArray =
[ChildNumberComponent(0),
ChildNumberComponent(1),
ChildNumberComponent(2),
ChildNumberComponent(3),
ChildNumberComponent(4),
ChildNumberComponent(5),
ChildNumberComponent(6),
ChildNumberComponent(7),
ChildNumberComponent(8),
ChildNumberComponent(9)];
```
という値が格納されることになります。論理的に。
関数型プログラミングに少し慣れていれば、特に難しいことではないでしょう。
`ChildrenNumberComponent10`の設計はこうなります。
```jsx
var ChildrenNumberComponent10 = () => {
var elArray
= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(ChildNumberComponent);
//number array transforms to element array
var el = (<div>{elArray}</div>);
return el;
};
```
全てのコードは
###jsx
https://jsfiddle.net/r4y5kdoq/7/
```
var ChildNumberComponent = (number) => (
<div>child{number}</div>
);
var ChildrenNumberComponent10 = () => {
var elArray
= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(ChildNumberComponent);
//number array transforms to element array
var el = (<div>{elArray}</div>);
return el;
};
var mount = ReactDOM.render(ChildrenNumberComponent10(), document.getElementById('container'));
```
####Webブラウザの表示結果
>child0
child1
child2
child3
child4
child5
child6
child7
child8
child9
もちろん、関数型プログラミングなので、
繰り返しのフロー、命令形のコードを書くことはありません。
React JSXで、統合的に宣言型コーディングすると何故良くなるのか?というのは、**何故、関数型プログラミングが良いのか?というのとまったく同じ事を語ること**であり、まったく同じ理由なので、その辺りは延々と[本稿の冒頭で引用している記事](http://kenokabe-techwriting.blogspot.jp/2015/04/iq145.html)やその延長の著書で解説しているのでそちらを参照してください。
#Facebook-Immutable を使ってさらに関数型プログラミングでReactする
もちろん、
0-9の配列、`[0,1,2,3,4,5,6,7,8,9]`を用意する、というのは、言うまでもなくスマートなアプローチではないですから、ここも関数型プログラミングにします。
JSFiddleのHTMLコードには、
```
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.7.6/immutable.min.js"></script>
```
とライブラリへのポインタを追加することで、著書でも解説している、
Facebookのもうひとつの関数ライブラリ、
[Facebook-Immutable](http://facebook.github.io/immutable-js/)
が活用できるようになります。
npmインストールしてWebPackする場合には、
https://github.com/kenokabe/stateless-react/blob/master/index.jsx
の通り、
```
var Immutable = require('immutable');
```
とすれば利用可能になります。
関数ライブラリ、Immutableを使うと、
配列、`[0,1,2,3,4,5,6,7,8,9]`を用意したければ、
```
Immutable.Range(0, 10).toArray()
```
とすれば、良いので、
```
var elArray
= Immutable.Range(0, 100).toArray().map(ChildNumberComponent);
```
となるでしょう。
戯れに、10でなく、100としても、単に数値の変化だけです。
全てのコードは
###jsx
https://jsfiddle.net/r4y5kdoq/8/
```jsx
var ChildNumberComponent = (number) => (
<div>child{number}</div>
);
var ChildrenNumberComponent100 = () => {
var elArray
= Immutable.Range(0, 100).toArray().map(ChildNumberComponent);
var el = (<div>{elArray}</div>);
return el;
};
var mount = ReactDOM.render(ChildrenNumberComponent100(), document.getElementById('container'));
```
となります。
####Webブラウザの表示結果(中略)
>child0
child1
child2
child3
child4
child5
child6
child7
child8
child9
child10
child11
child12
child13
child14
child15
child16
...........
...........
...........
child93
child94
child95
child96
child97
child98
child99
となります。
以上で、
FRPを必要としない静的なドキュメントを、
HTMLからJSXへ移行させる基礎固めは終了です。
オーソドックスなReactの手法では、通常、
`ReactComponent`は、
`<ReactComponent custom={9}/>`
などとし、
`props.custom`という形式をもって引数にアクセスしなければいけないのですが、0.14以降その必要性がまったく認められませんし、この記法でやると非常に見通しが悪くなると考えます。
Stateless functional components / Statelessな関数型コンポーネントという本質、本文を考えると、素直に直接、バニラJSの関数の引数として受け渡す形式でコードするのが道理であると思います。
おそらく、この解説で、時間変化を取り扱わない静的なHTMLページをReact JSXに移行することはだいたい出来るはずです。もちろん既存のテンプレートエンジン、プラグインなどをふんだんに利用しているページをなんでも移行できるという意味ではなく、スキルとして静的なHTMLページをより見通しよく冗長性を排除しながら再構築できるはずである、ということです。
時間変化を取り扱わない動的なWebアプリケーションをReactで実現するためには、改めてFRPをReactでどのように具現化するか、より注意深く考察しながら取り組む必要があります。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment