サンプルコードと同じ天気予報をFlexGridで表示
以下ではFlexGridをReactで表示していきます。図8のサンプルでは、図2で通常の表を利用して表示していた天気予報をFlexGridで表示します。
実装方法を以下で説明します。まず、FlexGridのパッケージを追加するため、ClientAppフォルダーでリスト1のコマンドを実行します。「@grapecity/wijmo.react.grid」が、React対応のFlexGridパッケージです。
npm install @grapecity/wijmo.react.grid
次にcomponents配下に、追加するコンポーネントに対応するWijmoFlexGrid.jsを追加して、リスト2の通り実装します。
import { Component } from 'react'; // WijmoのCSS、FlexGridのコンポーネントをインポート ...(1) import '@grapecity/wijmo.styles/wijmo.css'; import { FlexGrid, FlexGridColumn } from '@grapecity/wijmo.react.grid'; // FlexGridを表示するコンポーネント ...(2) export class WijmoFlexGrid extends Component { // コンストラクター ...(3) constructor(props) { super(props); // stateの初期値を設定 ...(4) this.state = { forecasts: [], loading: true }; } // コンポーネント配置(マウント)時の処理 ...(5) componentDidMount() { // データを取得 ...(6) this.populateWeatherData(); } // コンポーネントを表示する処理 ...(7) render() { // 表示内容 ...(8) let content; // ロード中(state.loading == true)の場合 ...(9) if (this.state.loading) { content = <p><em>Loading...</em></p> } // ロード完了(state.loading == false)の場合 ...(10) else { content = // FlexGrid:グリッド全体を表す ...(11) <FlexGrid itemsSource={this.state.forecasts} isReadOnly={true}> {/*FlexGridColumn: グリッドの1列を表す ...(12)*/} <FlexGridColumn binding="date" header="日時" width={280} /> <FlexGridColumn binding="temperatureC" header="温度(摂氏)" width={120} /> <FlexGridColumn binding="temperatureF" header="温度(華氏)" width={120} /> <FlexGridColumn binding="summary" header="サマリー"></FlexGridColumn> </FlexGrid> } // 表示内容を返却 ...(13) return content; } // データを取得 ...(14) async populateWeatherData() { // weatherforecast APIからデータを取得 ...(15) const response = await fetch('weatherforecast'); // 取得データをJSONとして解釈 ...(16) const data = await response.json(); // 取得したデータと、ロード完了(loading = false)をstateに設定 ...(17) this.setState({ forecasts: data, loading: false }); } }
リスト2の内容を説明します。(1)でWijmoのCSSやFlexGridのコンポーネントをインポートします。コンポーネントの実装(2)では、まずコンストラクター(3)で、Reactで利用する内部状態(state)を初期設定します(4)。stateには、表示する天気予報の内容forecastsと、ロード中かどうかを表すloadingを含みます。
(5)のcomponentDidMountは、コンポーネントがページに配置(マウント)された時に実行されるReactのライフサイクルメソッドです。ここでは(6)の通り、後述するデータ取得処理を実行します。
(7)のrenderは、表示内容を返却すると画面に描画してくれるReactのメソッドです。まず(8)で、表示内容を表す変数contentを用意します。state.loadingを参照して、データがロード中の場合は(9)のロード中表示、ロード完了の場合は(10)のグリッド表示がcontentに代入されて、(13)で返却されます。この処理により、state.loadingが変更された時にReactがロード中とロード完了後の処理を自動的に切り替えます。
ロード完了後の表示(10)内にFlexGridを記述します。グリッド全体を表す<FlexGrid>コンポーネント(11)内に、グリッドの1列を表す<FlexGridColumn>コンポーネント(12)を列の数だけ配置します。<FlexGridColumn>コンポーネントでは、表示するデータ名をbindingに、ヘッダー文字列をheaderに、列の幅をwidthに、それぞれ指定します。
(6)で呼び出されるデータ取得メソッドpopulateWeatherData(14)では、ASP.NET Coreで実装されているweatherforecast Web APIからデータを取得(15)後、(16)の処理でデータをJSONとして解釈し、(17)でstateのforecastsにそのデータを設定するとともに、loadingにfalseを設定してロード完了を指定します。
リスト2のコンポーネントを表示するため、画面上部メニューに対応するNavMenu.jsにリンクを追加します(リスト3)。
<ul className="navbar-nav flex-grow"> (略) <NavItem><!-- 追加 --> <NavLink tag={Link} className="text-dark" to="/wijmo-flexgrid">Wijmo FlexGrid</NavLink> </NavItem> </ul>
さらに、App.jsのrenderメソッド内に定義されているルーティングの設定に、リスト2のコンポーネントに対応した記述を追加します(リスト4)。
render () { return ( <Layout> (略) <Route path='/wijmo-flexgrid' component={WijmoFlexGrid} /><!-- 追加 --> </Layout> ); }
以上の実装により、図8の通り、画面右上に追加されたリンクをクリックして、FlexGridで天気予報を表示するコンポーネントを画面表示できます。
[補足]Wijmoのライセンス設定
上記の実装だけでは、Wijmoはトライアル版として動作します。正式版にするには、ライセンスキーを設定するリスト5の実装をindex.jsに追加します。
// Wijmoのライセンス設定 import * as wjcCore from '@grapecity/wijmo'; wjcCore.setLicenseKey('<ライセンスキー>');
ASP.NET Coreで独自のAPIを作ってFlexGridに表示させる
図8の例では、Visual Studioが生成した天気予報のWeb APIを表示させてきましたが、以下では独自のAPIを実装してFlexGridで表示させる方法を説明します。図9のサンプルでは、CodeZineのWebページが提供しているRSSをサーバー側Web APIで読み込んでクライアント側に渡し、FlexGridで記事のタイトル・URL・公開日時を表示します。
まず、サーバー側でRSSを処理するため、NuGet パッケージ マネージャーでMicrosoft.SyndicationFeed.ReaderWriterパッケージを検索してインストールします。
次に、Controllers/RSSFetchController.csファイル(リスト6)を生成して、Web APIの処理を実装します。
[Route("api/[controller]")] [ApiController] public class RSSFetchController : ControllerBase { [HttpGet] public async Task<List<RSSElem>> GetAsync() { (後述) } }
クラスに付与した[Route("api/[controller]")]、[ApiController]属性により、「api/RSSFetch」というパスに対応するWeb APIであることを指定します。GetAsyncメソッドに付与された[HttpGet]属性は、HTTP GETでのアクセスで実行される処理であることを表します。GetAsyncメソッドの実装はリスト7の通りです。
(略:HttpClientでCodeZineのRSSを読み込んでXmlReaderを生成) // RSSを読み込むRssFeedReaderを生成 ...(1) var feedReader = new RssFeedReader(xmlReader); var elemList = new List<RSSElem>(); // RSSを読み込み ...(2) while (await feedReader.Read()) { switch (feedReader.ElementType) { // 読み込んだ項目がRSSのItemだった場合 ...(3) case SyndicationElementType.Item: // itemの内容を読み込んでRSSElemオブジェクトに代入し、リストに追加 var item = await feedReader.ReadItem(); var oneElem = new RSSElem() { Title = item.Title, Link = item.Links.First().Uri.ToString(), PubDate = item.Published.LocalDateTime }; elemList.Add(oneElem); break; } } // RSSElemリストを返却(JSONのAPI戻り値が生成される) ...(4) return elemList;
CodeZineのRSSをアクセスするHttpClientから、RSSをXMLとして読み込むXmlReaderクラスのオブジェクトxmlReaderを取得する処理の後、(1)でxmlReaderからRSSを読み込むRssFeedReaderを生成します。RSSの各要素をwhileループ(2)で読み込み、その要素タイプ(ElementType)がアイテム(SyndicationElementType.Item)だった場合(3)、そのタイトル、URL、公開日時をRSSElemクラス(クラス実装はサンプルコード参照)のオブジェクトに格納してリストに追加します。
最後に(4)で、RSSの全アイテムデータが格納されたリストを返却します。この処理で、ASP.NET Coreのフレームワークにより、リスト内容がJSON文字列に変換されてAPIの戻り値として返却されます。
Web APIの戻り値をFlexGridで画面に表示する処理は、<FlexGridColumn>に指定する列名が異なる程度で、ほぼリスト2と同一です。詳細はサンプルコードを参照してください。
[補足]Reactプロジェクトのプロキシー設定
Visual Studio 2022のReactプロジェクトを開発環境で実行すると、Reactで実装したWebページをホストするNode.jsのWebサーバーと、Web APIをホストするASP.NET CoreのWebサーバーが同時に動作します。これらのサーバーはオリジン(ホスト名+ポート番号)が異なるため、いわゆる同一オリジンポリシーにより、Node.jsのWebサーバーから取得したWebページがASP.NET CoreのWebサーバーが提供するWeb APIへアクセスできません。
そのため、Visual Studio 2022のReactプロジェクトでは、Node.jsのWebサーバーがASP.NET CoreのWebサーバーのプロキシーとなって、Web APIへのアクセスを中継する設定が行われます。設定を行うのは表1、No.8のsetupProxy.jsで、中継するURLのパスをファイルに記述します(リスト8)。
const context = [ "/weatherforecast", "/api" // プロキシーが/api配下を中継するように設定 ...(1) ];
リスト6のWeb APIは「api/RSSFetch」というパスでアクセスされるため、プロキシーが中継対象にするパスを(1)の通り追加する必要があります。(1)の記述により「/api」配下の任意のパスが中継対象となります。
まとめ
本記事では、Visual Studio 2022のReactテンプレートで生成されたReactのWebページに、グレープシティのUI部品Wijmoに含まれるグリッド部品FlexGridを利用する方法を説明しました。FlexGridは、Reactのコンポーネントとして定義されるため、React本体とシームレスに利用できます。ASP.NET CoreのWeb APIと組み合わせる方法も説明しました。