1 RazorによるMVCアプリケーション
2 CRUDページとRazorを見る
3 ReactでSPAを作ってみた ←今回
今回のテーマ
今回はReact.jsを用いてSPA(シングルページアプリケーション)を 作ってみます。 ASP.net coreでSPAを作成する場合、普通はBlazorを使うのだと思われますが プロジェクト作成すると「React.js」があったので、 折角だから使ってみようと思いました。今回はこんなものを作ってみます。
非常に簡単なWebアプリを作ってみたい!って人がいたら
いつもおみくじアプリを薦めてます。
JavaScriptによるおみくじ表示と
引いた人リストによるバックエンドとのやりとりで
Webアプリの練習になるかなーと思ってます。
ちなみに普段SPA作る際は、Vue.jsを使用しているので
今回このためにReactを学びました。
そのため、よくわかってない付け焼き刃なReactを書いているので、
色々間違ってたり、あり得ないソースコードになってると思います...
(プロジェクト作成にはAngularもあるのに、なぜかVueは無かった...)
Reactプロジェクトの作成
いつものようにVisual Studioを用いてプロジェクトを作成しましょう。 ![プロジェクト作成1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595683/89933d18-8dbe-5179-aeb4-14e11f04cb1a.png) ![プロジェクト作成.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595683/75180d95-67ba-e068-e396-2221a5ad0e56.png) ![プロジェクト作成_React.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595683/a0d35d23-16c6-1acb-438d-7635a9d8a732.png) ASP.net core webアプリケーションを作成し React.jsを選択します。 React内で大掛かりなデータやりとりがないとされるため 今回はReact.jsで行います。(Reduxは使いません。)プロジェクトが出来たところで、サンプルページを開いてみましょう。
初回実行少々時間がかかります。
(npmが動いでたようなので、環境をインストールしてるのかな?)
・ASP.net coreとC#
・React
・Bootstrap
を使用してます!ってメッセージが出ます。
画面上のナビゲーションバー(ヘッダー)に
いくつか項目がありますね。
[Counter]を押したら、ボタンカウンターが出ました。
5回押したら5カウントされました。
[Fetch Data]を押したら、天気予報?が出ました。
5日間とも同じ時刻なのに、気温が偉く変わってますね-
-9℃の2日後に39℃になるって、どんな地域なんでしょうか?笑
JSファイルを編集しておみくじを作る
Reactのファイルを編集して、おみくじを作っていきます。プロジェクトを作成した際のファイル構成は下記の通り
srcフォルダの中にjsファイルが入っています。
メイン画面の「App.js」と、componentフォルダにコンポーネントファイルが入ってますね。
(Omikuji.jsは後から作ったファイルです。)
メイン画面の「App.js」の中身を見てみましょう。
import React, { Component } from 'react';
import { Route } from 'react-router';
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { FetchData } from './components/FetchData';
import { Counter } from './components/Counter';
import './custom.css'
export default class App extends Component {
static displayName = App.name;
render () {
return (
<Layout>
<Route exact path='/' component={Home} />
<Route path='/counter' component={Counter} />
<Route path='/fetch-data' component={FetchData} />
</Layout>
);
}
}
コンポーネントをインポートして、ルーティングで表示をわけていますね。
今回はルートディレクトリの{Home}コンポーネントをおみくじにしてみましょう。
import React, { Component } from 'react';
import './NavMenu.css';
let fortune = ["Daikichi", "Chukichi", "Kichi", "Shokichi", "Suekichi", "Kyo", "Daikyo"]; //運勢リスト
export class Home extends Component {
constructor(props) {
super(props); //propsを継承
this.state = { // this.state
message: "Please draw Omikuji !!", //初期メッセージ
displayName: "", //引いた人の名前
index:0, //運勢インデックス
}
this.drawOmikuji = this.drawOmikuji.bind(this); //メソッドをクラスにバインド
this.changeName = this.changeName.bind(this); //メソッドをクラスにバインド
}
drawOmikuji(e) { //おみくじを引くメソッド
this.setState(state => ({ //stateの変更
index: Math.floor(Math.random() * fortune.length), //ランダムで運勢インデックスを作成
message: this.state.displayName + "'s fortune is " + fortune[this.state.index]//メッセージを変更
}));
}
changeName(e) { //名前入力したら名前を取得
this.setState({ displayName: e.target.value }); //名前入力されたらstateのdisplayNameに名前を入れる
}
render () {
return (
<div>
<h1>Hello, Omikuji!</h1>
<div className="omikujiPadding row">
<input type="text" className="form-control col-6" placeholder="Your name" onChange={this.changeName} />
<input type="submit" className="btn btn-primary col-3" value="Draw Omikuji" onClick={this.drawOmikuji} />
</div>
<h2 className="messageStyle">{this.state.message}</h2>
</div>
);
}
}
画面のようにおみくじを実装しました。
運勢をリストにして、おみくじを引くときにランダムで
運勢リストから運勢を取り出します。
Reactの仕様?なのか、配列はclassの外で作らないと使えないですね。
はじめはclassの中に「static fortune=[]」と入れましたが、
Uncaught TypeError: Cannot read property 'length' of undefined
が表示されて使えませんでした。
名前をGeorgeにして、「Draw Omikuji」でおみくじを引くと
メッセージが「Georgeの運勢は 吉」と出ました。
ちなみに日本語だとエンコードの関係で文字化けたため、英語にしてあります。
引いた人リスト
実際のおみくじは、大凶が出るとおみくじを枝に結んで返しますね。 そのように、引いたら返すつもりで、引いた報告をする機能をつけてみます。 上イメージ図のように、引いた人の記録がテーブルに並ぶ感じにします。ここで、データを記録したり表示することが発生するため、バックエンドとの通信が必要になります。
ReactとASP.NET coreはどのようにしているのか?を探してみたところ
FetchData.js(天気予報コンポーネント)にヒントがありました。
async populateWeatherData() {
const response = await fetch('weatherforecast');
const data = await response.json();
this.setState({ forecasts: data, loading: false });
ルート「weatherforecast」にfetchして
そこからjsonで天気データを受け取っているようです。
ファイルを色々調べてみると、「Controller」の中に「WeatherForecastController.cs」という
天気データをReactに送るコントローラが見つかりました。
つまり、リクエストに対してjsonを返す Web APIになっているのだと思われます。
ということで、引いた人一覧クラスとそのコントローラーを作って
おみくじ返納Web APIを実装していきたいと思います。
using System;
namespace ReactOmikuji
{
public class DrawedList
{ public int ID { get; set; } //スキャフォールディング作成時の慣例
public string Name { get; set; }
public string Fortune { get; set; }
public DateTime Date { get; set; }
}
}
引いた人一覧クラス「DrawedList」を作成します。
次に、「Controller」フォルダを右クリックし
「追加」→「コントローラ」→「API \ EFを使用したアクションがあるAPIコントローラ」
でコントローラを作成します。
Razorのスキャフォールディングと同じ要領で、コントローラを作成します。
コントローラにアクセスしたらAPIが動くように、Routeの中を書き換えます。
[Route("drawedlist")]
[ApiController]
public class DrawedListsController : ControllerBase{
private static readonly string[] NameSample = new[] //リストに載せる名前サンプル
{
"A", "B", "C"
};
private static readonly string[] FortuneSample = new[] //リストに載せる運勢サンプル
{
"Daikichi", "Kichi", "Daikyo"
};
private readonly ReactOmikujiContext _context; //コントローラー使用するためのオブジェクト
public DrawedListsController(ReactOmikujiContext context) //コントローラ使用するためオブジェクトを処理
{
_context = context;
}
// GET: DrawedList
[HttpGet]
public IEnumerable<DrawedList> Get() //DrawedListにアクセスした際の処理
{
return Enumerable.Range(0,3).Select(index => new DrawedList //名前・運勢・引いた日付を
{
Date = DateTime.Now.AddDays(index),
Fortune = FortuneSample[index],
Name = NameSample[index]
})
.ToArray(); //配列で返す
}
}
「drawedlist」にアクセスすれば、Web APIが使えるようになりました。
今回は、「drawedlist」に行くと引いた人リストがjsonで返るようになってます。
SQL Serverは使用せず、いつも同じデータが出るようになってます。
(途中からSQL Serverがおかしくなり、使えなくなってしまった...)
jsonが出力されているのが確認できました。
これを受け取り、表にするコンポーネントを作ってみましょう。
import React, { Component } from 'react';
export class DrawedList extends Component {
constructor(props) {
super(props);
this.state = { drawedlist: [], loading: true };
}
componentDidMount() { //コンポーネント起動時にする処理
this.populateDrawedList(); //jsonデータをstateに入れる処理
}
static renderListTable(drawedlist) { //引いた人リストをテーブルに表示するhtml
return (
<table className='table table-striped' aria-labelledby="tabelLabel">
<thead>
<tr>
<th>Name</th>
<th>Fortune</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{drawedlist.map(drawedlist =>
<tr key={drawedlist.id}>
<td>{drawedlist.name}</td>
<td>{drawedlist.fortune}</td>
<td>{drawedlist.date}</td>
</tr>
)}
</tbody>
</table>
);
}
render() { //レンダー
let contents = this.state.loading //表示させる中身オブジェクト
? <p><em>Loading...</em></p> //読み込みに時間がかかると Loadingと表示
: DrawedList.renderListTable(this.state.drawedlist); //読み込めたら表を表示
return (
<div>
<p>This component demonstrates fetching data from the server.</p>
{contents}
</div>
);
}
async populateDrawedList() { //バックエンドと通信して、引いた人リストを取得
const response = await fetch('drawedlist'); //drawedlistにアクセス
const data = await response.json(); //jsonデータを取得
this.setState({ drawedlist: data, loading: false }); //jsonデータをstateに入れる
}
}
結構長くなってしまいましたが、テンプレートにある天気予報取得の
「FetchData.js」をそのまんま真似しただけです。
起動時にFetchでDBに接続し、データを取得
↓
データをstateに入れる
↓
stateをmapで全部表示される
とやって表示させているだけですね。
最後にHome.jsに<DrawedList />
を入れたら
引いた人リストが表示されました。
ただし、現在は表示だけで
おみくじを引いたら新しく追加される機能はまだついていません。
SQL ServerやMySQLとの通信が出来たら、また挑戦してみようと思います。
まとめ
長くなってしまいましたが、おみくじを一応作ってみた。 React.jsとASP.NET Coreでアプリを作ってみて感じたことは ・おみくじであればFirebaseでよい(ASP.NET Coreの必要がない) ・ASP.NET Coreのアドバンテージは、独自のWeb APIを作る場合 ・Reactは(Vueと比べて)Javascript感がある といったところでしょうか。初めて触ったReactですが、Javascriptを触っている感じがして
個人的にはVueよりも楽しめた気がします。
それから、ASP.NET CoreでSQL Serverと通信する場合は
Entity Frameworkというのを使うみたいです。
このEntity Frameworkを使いこなせば、MySQLが使えるのかなーと思います。
いずれチャレンジしてみたいです。
次回はBlazorを使ってSPAを作ってみたいと思います。
参考文献
https://docs.microsoft.com/ja-jp/aspnet/core/client-side/spa/react?view=aspnetcore-5.0&tabs=visual-studio Microsoftの公式ドキュメントです。https://ja.reactjs.org/
https://www.shuwasystem.co.jp/book/9784798056920.html
React.jsの公式ドキュメントと
書籍「React.js & Next.js超入門」です。
この2つを見ながらReactを実装しました。
https://github.com/Sho-Zhao/ReactOmikuji.git
Githubに載せています。