tekitoumemo’s diary

思ったことを書くだけ。長文版Twitter

SPAじゃないReactを.Net Coreで扱う

ちょっと特殊なReactの使い方を説明します。MVCで部分的にJqueryを使っていることが多いと思いますが、そのJqueryで作った部分がReactに置き換わる形です。ちなみに業務でAngularは触っているのですが、Reactは触っていませんので超ド素人です(通勤で調べて今試した感じ(笑))。なので、Reactの説明と言うよりは、.Net Coreのテンプレートをどう改造すれば部分コンポーネントとして扱えるかって記事になります。

なぜReactなのか?

ReactはViewに特化したフレームワークなので手軽に始められそうっていう浅はかな考えがきっかけ。フルスタックなAngularと違って最低限なライブラリしか用意されてないらしいので、無理にJSで作ろうと無茶な開発をしないっても大きいです。あとReact Nativeがあるから学習するなら一番コスパ高いです。

フルスタックの方が良いのでは?

個人的な意見ですが、今の段階でフルスタックなJSを使ってWEBサービスは作らない方が良いと思います。Angularなんか割となんでもできるので、サーバーサイドで作るかフロントで作るか結構曖昧になってしまってサーバーでもフロントでも同じ処理があるじゃんってオチになりがちな印象があります。さらにコンポーネントを分けたはいいものの、結局Input、Output、ViewChild、Subjectなど多用してわけわからなくなる状況に陥りがちです(前の現場はヒドかった。。)時間と意欲があればなんでも良いと思いますけどね。

で本題ですが、SPAじゃないReactとは以下の画像のような感じをイメージしてもらえればと思います。
f:id:tekitoumemo:20180608223633p:plain

緑がMVCで出力しているViewで水色、ピンクがReactのそれぞれのコンポーネントになっています。SNSだったらいいね機能、コメント機能でコンポーネントを分けられるので、綺麗に作れます。昔JquerySNSチックなので作ったのですが、メンテしづらいコードになっちゃいました。。これをJSフレームワークで作れたら結構綺麗になっただろうなーと思います。このサイトです(宣伝)

作り方

dotnet coreのテンプレートを使用しますので、以下のコマンドを入力します。特にdotnetに限ったことじゃないですが圧倒的に楽です。

dotnet new react -o {ディレクトリ名}

次にNodeのパッケージをインストールしてきます。

npm i

これでテンプレートは動くはずです。

boot.tsxを改造する

テンプレートだと以下のコードになっているはずです。

import "./css/site.css";
import "bootstrap";
import * as React from "react";
import * as ReactDOM from "react-dom";
import { AppContainer } from "react-hot-loader";
import { BrowserRouter } from "react-router-dom";
import * as RoutesModule from "./routes";
let routes = RoutesModule.routes;
function renderApp() {
    // This code starts up the React app when it runs in a browser. It sets up the routing
    // configuration and injects the app into a DOM element.
    const baseUrl = document.getElementsByTagName("base")[0].getAttribute("href")!;
    ReactDOM.render(
        <AppContainer>
            <BrowserRouter children={ routes } basename={ baseUrl } />
        </AppContainer>,
        document.getElementById("react-app")
    );
}

renderApp();

// Allow Hot Module Replacement
if (module.hot) {
    module.hot.accept("./routes", () => {
        routes = require<typeof RoutesModule>("./routes").routes;
        renderApp();
    });
}

これはid="react-app"と記載されているところに表示されます。SPA用のマウントなのでルーティング用のパラメータが指定されてます。このReactコンポーネントのマウントをベタがきします。

import "./css/site.css";
import "bootstrap";
import * as React from "react";
import * as ReactDOM from "react-dom";

import { Counter } from "../ClientApp/components/Counter";
import { FetchData } from "../ClientApp/components/FetchData";
function renderApp(): void {
    // これ
    ReactDOM.render(<Counter />,document.getElementById("counter-app"));
    ReactDOM.render(<FetchData />,document.getElementById("fetch-app"));
}
renderApp();

上記のコードを噛み砕きます。
まずはコンポーネントをimportします。

import { Counter } from "../ClientApp/components/Counter";
import { FetchData } from "../ClientApp/components/FetchData";

次にコンポーネントをマウントします。

    ReactDOM.render(<Counter />,document.getElementById("counter-app"));
    ReactDOM.render(<FetchData />,document.getElementById("fetch-app"));

これでdocument.getElementByIdで指定したタグにコンポーネントが紐づきます。Railsだとreact-railsっていうgemがあるみたいなんだけどnugetにはないのかな?

次にコンポーネント側の修正します。
以下のコードを修正します。

export class Counter extends React.Component<RouteComponentProps<{}>, CounterState> {
// ↓に変更する
export class Counter extends React.Component<{},any> {

テンプレートのままだとboot.tsxでエラーになりますので「RouteComponentProps<{}>, CounterState」を排除しましょう。Stateはコンポーネント内で定義すればいらないので排除しちゃって良いっぽいです(正直よくわかってない)

これでマウントされたコンポーネントがつかえるようになります。簡単でしたが意外と探しても少なかったので調べました。このソースコードgithubにおいたので興味ある方は試してみてください。これからReactバリバリ使う予定なので、もっと理解深めてブログに書いてきます。次は.NetCore MVCにReactを入れるミドルウェアとかの紹介かな<さっそくReactじゃない
github.com

ちなみに

.Net CoreのテンプレートだとTypeScriptがReactでもついてる!やば最高。

"typescript": "2.4.1",

参考
非SPAなサービスにReactを導入する - クックパッド開発者ブログ
【react】jqueryメインの非SPAシステムの特定ページでのみreactを導入してみたのでメモ - とりあえずphpとか