ぷろぐらみんぐ帳

C#とかJavaScriptとか

VisualStudioで生のReact.js+linq.js

前々からやってみたかったReact.jsを触ってみた。詳しいことはまだちゃんと把握していないぺーぺーなのだが、思想が.NETのWPFやRxそのものなので親近感があったので。.NETっぽくしたかったのでlinq.jsも使ってみた。結論から言うと意外と相性が良かった。

プロジェクト作成

VisualStudio2015の例。せっかくなのでReactもlinqもNuGet経由でインストールする。

  1. ファイル→新規作成→プロジェクト
  2. 新しいプロジェクトが出てきたら、テンプレート→Visual C#→Web→「ASP.NET Web Application」
  3. New ASP.NET Projectが出たら、とりあえず「Empty」を選択
  4. Configure Microsoft Azure Web Appが出てくるが、関係ないのでキャンセルを選択
  5. プロジェクトができたら、プロジェクトを右クリック→追加→新しい項目
  6. 新しい項目の追加から、Visual C#→Web→「HTMLページ」を選択、名前を「main.html」とする
  7. main.htmlを右クリック→スタートページに設定
  8. プロジェクトを右クリック→NuGetパッケージの管理
  9. 参照から、「React.js」と「linq.js」を検索し、インストール
  10. React.jsは「Scripts/react」以下に、linq.jsは「Scripts」以下にインストールされている。

React.jsで静的なWebページを作る

簡単な例として表を作ってみる。ボタン操作等でDOMを書き換えるのはまた今度で。JSX記法はBabelをインストールしないといけないので、JSXなしで作ってみた(ちょっと面倒だけど意外といける)。このページが大変参考になった。 postd.cc まずHTML部分から。

<body>
    <script type="text/javascript" src="Scripts/react/react.js"></script>
    <script type="text/javascript" src="Scripts/react/react-dom.js"></script>
    <script type="text/javascript" src="Scripts/linq.js"></script>
    <div id="root"><!--ルートコンポーネント--></div>

    <script type="text/javascript">
    /* ここにReactのコードが入る */
    </script>
</body>

最初は、React.renderが非推奨になりReactDOM.renderが推奨になったので、react.jsだけでなくreact-dom.jsも外部ファイルから呼び出している。他にlinq.jsも呼び出した。以下。Reactのコード部分について。

まずは表示したいデータ。東海地方の4県の人口や県庁所在地、政令指定都市JSON形式で与えた。

var prefs = [
    { key: 1, name: "静岡県", prefectoralCapital: "静岡市", designatedCities: ["静岡市", "浜松市"], population: 369 },
    { key: 2, name: "愛知県", prefectoralCapital: "名古屋市", designatedCities: ["名古屋市"], population: 751 },
    { key: 3, name: "岐阜県", prefectoralCapital: "岐阜市", population: 202 },
    { key: 4, name: "三重県", prefectoralCapital: "津市", population: 181 }
];

これをtableとして表示する。行単位のクラスを定義する。

var Prefecture = React.createClass({
    propTypes: {
        name: React.PropTypes.string.isRequired,
        prefectoralCapital: React.PropTypes.string.isRequired,
        designatedCities: React.PropTypes.array,
        population: React.PropTypes.number.isRequired,
    },
    render: function () {
        var designated = "";
        if (this.props.designatedCities) designated = this.props.designatedCities.join(",");

        return React.createElement("tr", { key: this.props.name },
            React.createElement("th", { key: this.props.name + "_1" }, this.props.name),
            React.createElement("td", { key: this.props.name + "_2" }, this.props.prefectoralCapital),
            React.createElement("td", { key: this.props.name + "_3" }, designated),
            React.createElement("td", { key: this.props.name + "_4" }, this.props.population)
            );
    }
})

Reactの面倒なところに、各要素ごとにkeyを与えないといけない(これが結構ハマった)。tr要素だけにkeyを与えても、コンソールのエラーに

0x800a139e - JavaScript 実行時エラー: Warning: Each child in an array or iterator should have a unique “key” prop. Check the top-level render call using . See https://fb.me/react-warning-keys for more information.

と表示される。えっtrにkey与えたやん!とやっても一向にエラーが消えない。Stackoverflowを見たら似た現象があって、 stackoverflow.comtrだけじゃなくてtdやthにもkeyを与えろ」とのこと。なにそれめんどくさい。解決法にもあったが、Reactで表を作るときはtableで作るのではなく、CSSでdiv要素を使って表みたいなスタイルを定義してやるのが楽かもしれない。確かに、thやthにもkeyを与えるとエラーは消える。

表のコンポーネントを作っていく。

var tableElements = Enumerable.From(prefs).Select(function (p) { return React.createElement(Prefecture, p) }).ToArray();
var tableHeader = React.createElement("tr", { key: "header" },
    Enumerable.From(["県名", "県庁所在地", "政令指定都市", "人口(万人)"]).Select(function (header) {
        return React.createElement("th", { key: header }, header);
    }).ToArray());
tableElements.unshift(tableHeader);

普通はmap関数を使うが、linqでも普通にできる(だってこっちのほうが読みやすいし)。Reactのエレメントは子のエレメントを持っているという構造上、多分linqと相当相性いいんじゃないかと思う。最後にルートエレメントを作ってReactDOMにぶちこむ。

var rootElement =
    React.createElement("table", { key: "table" },
      React.createElement("tbody", { key: "tbody" }, tableElements)
    );

ReactDOM.render(rootElement, document.getElementById("root"));

結果はこちら。至って普通のtableである。
f:id:enjyuu:20170819050510p:plain
これだけといったらこれだけだが、Reactの記事あんまりないのでこんなへっぽこなものでも参考になれば幸い。もうちょっとひねって動的な操作をしてReactの本領発揮させたいところ。