React to nest vite

ReactとNestでWebアプリケーションを作る3回目です。 最初からやりたい場合はナビゲーションから初回を開いてください。

今回はフロントエンドのReactとサーバサイドのNestをつないでいきます。

最初に、ReactのURLと、nestのURLを分けることでアクセスの管理をしやすくします。 具体的にはURL中のパスが /api だったら、nestがアクセスを受け取るようにします。 myreactapp/server/src/app.controller.tsを以下のように変更します。

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller("api/messages") // @Controller() のカッコの中に"api/messages"を入れました。
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

ターミナルで以下を実行します。(前のページから続きでやっている場合は、すでにサーバが起動しているので不要です。)

npm run watch:server

http://localhost:3000/api/messages にアクセスして「Hello World! そして世界へ」と表示されれば成功です。 表示されたらCtrl+Cでサーバを停止しておいてください。

続きまして、ReactとNestをつなげていきます。 Reactにアクセスしてなにもすることがない場合、Nestに通信を回すということをします。

myreactapp/front/vite.config.ts を以下のように修正します。

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()], 
  //ここから
  server: {
    proxy: {
      "/api": {
        target: "http://localhost:3000/",
        changeOrigin: true
      }
    }
  }
  //ここまでを追加します。
})

次に、ReactとNestを同時に起動するようにします。 ターミナルでmyreactappディレクトリで以下のコマンドを実行します。

npm i npm-run-all

myreactapp/package.jsonを変更します。

{
  "name": "myreactapp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
    ,"watch:client": "npm run dev --prefix front"
    ,"watch:server": "npm run start:dev --prefix server"
    ,"watch": "run-p watch:**" (←この行を追加します。カッコは記入しないでください。)
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "npm-run-all": "^4.1.5"
  }
}

これで、一度のコマンドでReactとNestを起動できるようになりました。

コマンドを実行しておきます。

npm run watch

これでReactとNestが立ち上がりました。

次に、ReactからNestに通信します。

myreactapp/front/src/App.tsxを以下のように変更してください。

import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

function App() {
  const [count, setCount] = useState(0)

  const [message, setMessage] = useState("ロード中...");// この行を追加

  (async () => {// ここから
    const response = await fetch('/api/messages', { method: 'GET' });
    setMessage(await response.text());
  })(); //この行までを追加

  return (
    <>
      <div>
        <a href="https://vite.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
        <p>作ったった</p> 
        <p>{message}</p> {/* この行(</p>まで)を追加 */}
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  )
}

export default App

これでReactにNestの情報を渡して画面表示ができるようになりました。 http://localhost:5173 にアクセスしてください。

ReactにNestレスポンスを表示

このようにNestで出力した「Hello World! そして世界」という文字がReactに表示されていれば成功です。

少し、コードの解説をします。

  const [message, setMessage] = useState("ロード中...");// この行を追加

では、messageという値を画面で使えるように準備しています。 Nest=サーバから取得して表示するため、画面表示できるタイミングよりちょっと遅れて描画されなければなりません。 よって、デフォルトの内容を"ロード中"として。messageが取得できたら、messageを差し替えるためにsetMessageという変数をuseState()という関数を実行することで取得しています。

  (async () => {// ここから
    const response = await fetch('/api/messages', { method: 'GET' });
    setMessage(await response.text());
  })(); //この行までを追加

この4行は関数を定義して、即座に実行しています。非同期型=asyncな関数を実行するための1つの方法です。 (async()=>{})で関数を作って、その後の一番最後の () で実行しています。

その中の2行でサーバから値を取得しています。 fetch関数でNestの/helloにアクセスしてresponseを得ています。 response.text()でサーバからの値を文字列として取得できるので、setMessage()に渡してmessageに変更があったことをReactに伝え、画面表示をしています。

これで、ReactとNestをつなぐことができました。

続いてはNestでデータベースにデータを保存できるようにしていきます。