# ReadMdReact.htmlを順を追って解説。

[ReadMdReact.html]:ReadMdReact.html

[ReadMdReact.html](ReadMdReact.html) はjavascriptを使って、markdownのテキストデータをHTMLに変換してブラウザ上に表示する
プログラムです。

このページを、

```
  http://localhost/ReadMdReact.html?src=jslib/MathJax-demos-web/README.md
```

の様に、query(?src=/jslib/MathJax-demos-web/README.md)をつけて
呼び出すと、このsrcに指定されたURIの中身がHTMLに変換されて表示されます。

このおおよそ1ページのhtml/javascriptの中に、

 1. React DOMを使ったweb pageの作成
 1. JSXによるDOMの生成
 1. javascriptのfetchによる　Ajax　の取り扱い
 1. URLからのQuery の取り出し

が含まれていますので、javascript/Reactの概要を知ることのできるサンプルかと思い、ちょっと解説します。

## React/JSXの準備

ReactはjQuerry.jsに代わりjavascript上でDOMコンポーネントを効率よく、かつ安全に取り扱えると評判 (?) のjavascriptライブラリです。Reactでは(React)DOMコンポーネントをより簡便に記述できるJSXを使えます。JSXはbabel javascript ライブラリで、通常のjavascriptに変換された上で、ブラウザあるいはnode.jsなどのjavascript 処理系で実行されます。React環境では、変換されたjavascriptは React.js の API を呼び出す様に変換されます。
という事で、

```
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> 
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin> 
    <!--  babel for JSX -->
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
```
によって　react/react-dom/babelのjavascript ライブラリがCDN経由でロードされます。

開発中は、エラーの場所を特定するためにdevelopment.js版を使いますが、開発が終われば運用版の、

```
    <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"</script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
    <!--  babel for JSX -->
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
```
を使うことが推奨されています。

次の

```
    <!--  marked convers markdown text to html --->
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
```
は markdownのテキストを HTML に変換してくれる javascript ライブラリ marked を読み込みます。

## Reactの結果を受け取る `<div>` タグ
Reactが作成したDOMを受け取って表示するための containerとなる `<div/>` タグを `<body>` 中に作成します。
Reactからこの `<div/>` をcontainerとして指定するためにid アトリビュートが必須です。

```
    <div id="markdown_content" />
```

## Script セクション

### React.Componentの定義と、オブジェクトの作成

Reactでは、仮想DOMと呼ばれる Rect.Componet(の子クラス）のオブジェクトを作成し、
それを containerに渡して表示させるという流れになります。

```    
	class ReadMd extends React.Component {
          ..... 
	}
	const domContainer = ReactDOM.render(
      	<ReadMd />,  // ReadMd コンポーネントによって作られるDOMを、
      	document.getElementById('markdown_content') // id=markdown_content のDOMの子供として埋め込む。 
    );
```

JSXでの表現 `<ReadMd/>` は javascriptでの表現、`React.createElement(ReadMd)` と等価です。


### componentの状態変数

ReactのComponentには propとstateと呼ばれる component の内部状態を保持する仕組みが備わっています。prop内のアトリビュートは、immutable, つまり componentが作成されると変更することができません。実行時に変更される状態変数をcomponentに持たせるためにはstateを使う必要があります。


```
      constructor(props) {
	    super(props);
	    this.state = { __html:"" }; // for dangerouslySetInnerHTML
      }
```
で このクラスに "__html"という名前のアトリビュートを持つstateを定義しています。

### componentの中身を作成。 (render)
 
ReactコンポーネントはDOMオブジェクトと同じ様に、その中に子DOMオブジェクトを含むことができます。また、それ自身はHTMLのタグとして実現されます。　

```
      render() {
        return <div dangerouslySetInnerHTML={this.state} />
      }
```
がReactのシステムによって呼び出されると、この場合には、　出力 webページ上に　<div > タグが作成されます。　JSXを使うことで、html風の表記方法を用いてより複雑な DOMを作成することも可能です。　Reactでは通常 DOMオブジェクト経由でその子DOMや、contentsを作成します。これまでのjavascriptの様にinnerHTMLを直接操作することは避ける様になっています。ただここでは、使用しているmarkedプログラムからの出力は、HTMLのテキストですので、何とかしてinnterHTMLにこのHTMLを送り込んでやる必要があります。そこで使われるのが "dangerouslySetInnerHTML"というReact componentのアトリビュートです。このアトリビュートに渡す値は、”__html"というキーを持った辞書型データです。　ここではthis.stateに"__html"アトリビュートを持たせる事で、dangerouslySetInnerHTMLに this.staeの中身を割り当てています。この例の様に、JSXで
javascriptのexpressionの値を組み込む際は、{this.state}の様にブレースでjavascriptのexpressionを囲んで埋め込みます。

JSXでの表現 `<div dangerouslySetInnerHTML={this.state} />` は等価なjavascript 
```
    React.createElement(
	  'div',
      {dangerouslySetInnerHTML: this.state},
	  null
    );
```
に置き換えることが可能です。(別の言い方をすると、ReactはJSXなしでも使えます。)


### fetchによる外部データの取り込み。

constructor(), render()によってReact componetの実体と対応するHTML domオブジェクトが生成されるとReactは   componentDidMount()　メソッドを呼び出します。 Reactのドキュメントでは、
AJAXなどによる外部データの取り込みはこのメソッドを使うことが推奨されています。

```
	let SearchParams = new URLSearchParams(window.location.search);
```

では、ページのURLからquery部分を取り出して、変数 SearchParamsに割り当てています。
次に、

```
	let html=null;
	if (SearchParams.has("src")){  //query の中にsrcがあれば、
          html=fetch(SearchParams.get("src"));
	} else{ // 指定がなければ README.mdを変換しようとする。
	  html=fetch("README.md");
	}
```
によって queryの中に"src="が指定されていればそのuriから、またなければ"READM.md"から
変換するmarkdownのテキストを要求します。fetch()は 最近のwebbrowserに搭載されている
AJAXのためのAPIです。 fetchはpromiseと呼ばれるオブジェクトを値として返します。
promiseは, それまでのcallback関数を使ったやり方に変わって、
javascriptでの非同期処理を取り扱うために導入されました。
promiseを使った非同期処理では、then()メソッドを組み合わせる事で、これまで callbackを使っていた
処理を見やすく記述できる様になっています。then()メソッドの戻り値はpromiseオブジェクトとなっており、promise_object.then().then().then()...と言った連鎖を作ることができます。promiseオブジェクトにはcatch()メソッドも用意されており、エラーの例外処理もpromiseオブジェクトを使って記述できます。

```
	html.then(　//無名のpromise オブジェクト1
	  (response) =>{
	    if (!response.ok) {
	      throw new Error("HTTP error, status = " + response.status);
	    }
	    return response.text();
	  }
	).then(//無名のpromise オブジェクト2
	  (txt) => {
	    this.setState({ __html:marked(txt)});
	  }
	)
```
この例では、まずfetch()の戻り値であるpromiseオブジェクト(html)のthenメソッドで、レスポンスがokであるかをチェックし、okでなければエラー例外を発生します。OKであれば レスポンスから内容を text()関数を使って取り出します。　ここで注意すべきは、thenの引数は値ではなく関数オブジェクトそのものであるということです。then()の戻り値であるpromiseオブジェクト(無名のpromise オブジェクト1）は、fetch()が戻り値を取得した段階で、この関数オブジェクトが実行します(非同期の実行). この関数の実行が終了した時に、このオブジェクトのthen()によって処理関数が指定されていれば、実行結果をこの次のpromiseオブジェクト（無名のpromise オブジェクト2）の処理関数に渡して、実行します。

この関数では、レスポンスから取り出されたmarkdown textデータをmarked()関数でHTMLテキストに変換、このテキストを React Componet( ReadMd)のsteteに__htmlアトリビュートの値としてセットします。  

Reactは, 更新が必要なdomオブジェクトに対してrender()を適宜呼び出します。再びrender()関数が
呼び出されることで　最終的にwebページが更新されmarkdownを変換したHTMLの内容が表示されます。

## 最後に

駆け足で、Reactを使ったwebページの解説を行いました。JSX,AJAXなどの使い方の一例を示しました。

このweb ページでは、React, Babelなどの javascriptはCDNを使って導入していますが、複数のサイトからのjavascriptのロードやbabelによるJSXからjavascriptへのは実行時の負荷となることから、
webpackなどのツールを使ってパッケージ化を行うことがよく行われている様です。
ただ、Reactの使い方を試すだけであれば、webpackなどの環境を整備することなく、
CDNに頼るというのも一つのやり方かと思います。

## 参考URI
以下、このReadMdReact.html作成の際に参考にさせていただいたURIをいくつかあげておきます。

 * http://qitailang.small.jp/webtech/markdown_parser/index.html 

 * https://www.wakuwakubank.com/posts/699-javascript-markedjs/

 * https://ja.reactjs.org/docs/faq-ajax.html

 * https://ja.reactjs.org/docs/faq-ajax.html

