タスク管理ツールをReact + ASP.Coreで作る 03サンプルAPIのデータをクライアントサイドで表示する

[前回](https://qiita.com/mosuma/items/0afda530de5e8f979a20)の続きです



前回までで、webapiと、クライアントサイドの双方のひな型を作りました。
今のところどちらもテンプレートから生成したままで、プロジェクトが生成されて開発環境が立ち上がることの確認までが出来た状態です。


ここから、サーバーサイドのwebapiのデータをクライアントで表示する機能を作っていこうと思います。

### [index](https://qiita.com/mosuma/items/88e40dc44e7bff1a54d8)


## 今回やること

- サーバーサイド
    - 別ドメインからのアクセスを許容する
- クライアントサイド
    - webapiからデータを取得して表示するコンポーネントを作る
    - メイン画面から作ったコンポーネントを呼び出す



### サーバーサイドの更新(Startup.csを変更して別ドメインからのアクセスを許容)
ASP.NET Coreは、初期状態だと別ドメインからのアクセスを制限する設定がされています。
元々はCSRF等の攻撃に対策するための機能ですが、今回のアプリではサーバーサイドとクライアントサイドでドメインが異なるので、初期設定のままだとクライアントからのアクセスも制限されてしまいます。
そのため、以下の様にStartup.csを変更して、別ドメインからのアクセスを許容する設定を行います。




<details><summary>Startup.cs</summary><div>


```diff_c_sharp:Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;

namespace server_app
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

+       readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {

            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "server_app", Version = "v1" });
            });


+            services.AddCors(o => o.AddPolicy(MyAllowSpecificOrigins, builder =>
+            {
+                builder.AllowAnyOrigin()    // Allow CORS Recest from all Origin
+                       .AllowAnyMethod()    // Allow All Http method
+                       .AllowAnyHeader();   // Allow All request header
+            }));

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "server_app v1"));
            }

            app.UseHttpsRedirection();

            app.UseRouting();

+            app.UseCors(MyAllowSpecificOrigins);   // Add For CORS
+
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
```

</div></details>





### クライアントサイドの更新(WEB APIからデータを取得する機能と、それをメイン画面に表示する)
クライアントサイドに、サーバーサイドのAPI「WeatherForecast」からデータを取得し、テーブルに表示するコンポーネント「WeatherForecast.tsx」を作り、またApp.tsxでそれを呼び出します。



<details><summary>WeatherForecast.tsx</summary><div>

```diff_tsx:WeatherForecast.tsx
import { useEffect, useState } from 'react';

interface Forecast {
  date: Date;
  temperatureC: number;
  temperatureF: number;
  summary: string;
}

export const WeatherForecast = () => {
    
    
    const [loading, setLoading] = useState(true);
    const [forecasts, setForecast] = useState<Forecast[]>();
  
    useEffect(() => {
        populateWeatherData();
    }, []);
  
    const populateWeatherData = async () => {
        const response = await fetch('https://localhost:5001/weatherforecast');
        const data = await response.json();
        setForecast(data);
        setLoading(false);
    };
    
    if(loading) return <div>loading....</div>

    return (
        <div>
            <h1 id="tabelLabel">Weather forecast</h1>
            <p>This component demonstrates fetching data from the server.</p>
            <table className="table table-striped" aria-labelledby="tabelLabel">
                <thead>
                <tr>
                    <th>Date</th>
                    <th>Temp. (C)</th>
                    <th>Temp. (F)</th>
                    <th>Summary</th>
                </tr>
                </thead>
                <tbody>
                {forecasts && forecasts.map((forecast) => (
                    <tr key={forecast.date.toString()}>
                    <td>{forecast.date.toString()}</td>
                    <td>{forecast.temperatureC}</td>
                    <td>{forecast.temperatureF}</td>
                    <td>{forecast.summary}</td>
                    </tr>
                ))}
                </tbody>
            </table>
        </div>
    )
}
```


</div></details>




<details><summary>App.tsx</summary><div>

```diff_tsx:App.tsx
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { FetchData } from './WeatherForecast';

function App() {
  return (
-    <div className="App">
-      <header className="App-header">
-        <img src={logo} className="App-logo" alt="logo" />
-        <p>
-          Edit <code>src/App.tsx</code> and save to reload.
-        </p>
-        <a
-          className="App-link"
-          href="https://reactjs.org"
-          target="_blank"
-          rel="noopener noreferrer"
-        >
-          Learn React
-        </a>
-      </header>
-    </div>
+    <div>
+      <WeatherForecast />
+    </div>
  );
}

export default App;
```

</div></details>



## 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664470/990e3110-7f41-3bc5-e4a3-45c9ce952db3.png)




今回は以上です
続きは[次回](https://qiita.com/mosuma/items/ccdce8d079a9f209a675)です