プロジェクトの生成
最初に、実装のもととなるプロジェクトを作成していきます。
Reactプロジェクト
「TypeScriptを利用したReactプロジェクトの生成方法」をCopilot Chatに質問すると、図2の通り、Create React Appを利用する方法を提案してきました。
しかし、Create React Appを利用する方法は、Reactの古いページには記述があるものの、現在の公式ページには記述がなく、方法として古い点が気になります。そこで「create-react-appは古いのでは」とCopilot Chatに質問すると、図3の通りViteを利用した方法を提案してきました。
本記事ではこの提案に基づき、Viteを利用して、リスト1のコマンドでプロジェクトを生成します。「--template react-ts」は、TypeScriptを利用したReactプロジェクトのテンプレートを利用してプロジェクトを生成することを表します。
npm create vite@latest <プロジェクト名> -- --template react-ts
プロジェクト生成後、プロジェクトフォルダーで「npm install」コマンドでライブラリをインストールして、「npm run dev」コマンドを実行します。Webブラウザーで「http://localhost:5173/」にアクセスして、図4の通りWebページを表示できます。
[補足]GitHub Copilotの間違いは人間がフォローする
図2の手順では、最初にCreate React Appをインストールするよう案内されますが、次に実行する「npx create-react-app ...」コマンドでは、npxコマンドにより自動的にcreate-react-appパッケージをインストールして実行できるため、最初にCreate React Appをインストールしておく必要はありません。
Reactプロジェクトの生成法として(古い方法である)Create React Appを最初に提案してきたことも含め、GitHub Copilotでは人間が意図した正しい回答が常に得られるとは限りません。GitHub Copilotの提案が妥当かを判断するのは人間の責任です。
その意味で、Github Copilotを実作業に使う場合には、提案の妥当性を判断できるだけの最低限の知識(本記事では、Node.js、Express、Reactの概要程度)を持っておきたいところです。全く知らないことを教えてもらうより、大まかに知っていることを詳細に教えてもらう感じでGitHub Copilotを利用すると、良い結果が得られます。
Expressプロジェクト
Reactプロジェクトと同様、Copilot Chatにプロジェクトに「Expressを利用するNode.jsのプロジェクトを作成する方法」と質問すると、図5の通り提案されます。
提案された通りプロジェクトを作成していきます。プロジェクトフォルダーを作成し、その中で「npm init -y」コマンドを実行して、Node.jsプロジェクトを初期化します。
次に「npm install express」コマンドでExpressをインストールし、アプリケーションのファイル(index.js)をリスト2の内容で作成します。
const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello World!'); }); app.listen(port, () => { console.log(`Server is running at http://localhost:${port}`); });
リスト2の内容はGitHub Copilotに説明してもらいましょう。index.jsをエディターで開いて、Copilot Chatで「@workspace /explain #editor」コマンドを実行すると説明が表示されます。図6はコードの各行に説明のコメントを付与して表示した様子です。
続いて、図7の通り、各行の詳細が表示されます。
「node index.js」コマンドでリスト2を実行して、Webブラウザーで「http://localhost:3000/」にアクセスすると、「Hello World!」と表示されます。
プロジェクトに実装を追加
それでは生成されたプロジェクトをもとに実装を加えて、サーバー側のWeb APIとクライアント側のWebページを作っていきます。
ExpressプロジェクトにWeb APIを実装
まずExpressプロジェクトにWeb APIを実装します。index.jsをコードエディタで表示して、Ctrl+Iコマンドでインラインチャットを開き、「スマートフォンの一覧を返却する/phones API」と命令すると、図8の内容が提案されます。
提案の内容をリスト3に示します。brand(メーカー)とmodel(機種)からなるスマートフォンの一覧を格納したphones配列を(1)で生成し、(2)のres.jsonメソッドで、phones配列の内容を表すJSON文字列のレスポンスを返却します。
app.get('/phones', (req, res) => { const phones = [ // ...(1) { brand: 'Apple', model: 'iPhone 13' }, { brand: 'Samsung', model: 'Galaxy S21' }, { brand: 'Google', model: 'Pixel 6' } ]; res.json(phones); // ...(2) });
ReactプロジェクトにWeb APIへのアクセス処理を実装
次に、リスト3のAPIからデータを取得して表示するReact側の実装を実装します。Copilot Chatに「http://localhost:3000/phonesから、brandとmodelを含む配列をJSON文字列で受け取って、ReactのWebページに表示する処理を、TypeScriptで、App.tsxに実装したい」と、Web APIの仕様を含んだ質問を与えると、図9の通り提案してくれます。
図9で「実際のコードを示します。」に続いて提案されたコードはリスト4の通りです。
import React, { useEffect, useState } from 'react'; // Phone型の定義 ...(1) interface Phone { brand: string; model: string; } const App: React.FC = () => { // phones状態の初期化 ...(2) const [phones, setPhones] = useState<Phone[]>([]); // コンポーネントのマウント時にデータを取得 ...(3) useEffect(() => { const fetchPhones = async () => { try { const response = await fetch('http://localhost:3000/phones'); const data = await response.json(); setPhones(data); } catch (error) { console.error('Error fetching phones:', error); } }; fetchPhones(); }, []); // ...(3a) return ( // ...(4) <div> <h1>Phone List</h1> <ul> {phones.map((phone, index) => ( <li key={index}> {phone.brand} - {phone.model} </li> ))} </ul> </div> ); }; export default App;
(1)はbrandとmodelを含むPhone型の定義です。(2)のuseStateフックで、スマートフォンの一覧を保持するphones変数と、それにデータを設定するsetPhones関数を定義しています。(3)のuseEffectフックで、コンポーネントがマウントされたときにAPIのURL(http://localhost:3000/phones)にアクセスしてデータを取得し、setPhones関数でデータを格納する処理を記述します。
useStateフックの第2引数(3a)は、変更されたときにuseEffectフックを実行する変数の指定で、ここでは[](空配列)を指定することで、コンポーネントのマウント時のみにuseEffectフックが実行されるようにしています。最後に(4)で、phones変数の内容を画面に表示します。