🎄

LaravelプロジェクトにReact導入その1 -導入 & API連携編-

2023/12/20に公開

こんにちは、Webバックエンドエンジニアの@ShoHyblinxです。

現在運用中のポートフォリオのフロントエンドをReactに置き換えたので、その時の備忘録を書きます。

モチベーション

元々は当時業務で使っていたLaravelを学習する目的で、bladeでフロントエンドを作っていましたが、数年経った今、次のステップとしてフロントエンド周りをちゃんと理解する必要性を感じたことがきっかけです。

あとは自分の傾向として0→1を経験した方が理解度が高いので、そういった意味でも自分が気軽に扱える環境に導入してみるのがよいと考えました。

候補として考えたのはVue.js or React.jsでしたが、Vue.jsは既に別のサービスで使っているため、今回はReact.jsを使うことにしました。

目指す構成

変更前は一般的なLaravelプロジェクトの構成です(プロジェクトルートにapp/とかが作られてる構成ですね)。これを以下のように変更したい。

root/
 ├ backend/
  └ (既存のLaravelのバックエンド)
 └ frontend/
  └ (React化したフロントエンド)

やったこと

1. Reactプロジェクト作成

まずはルートディレクトリにfrontendディレクトリを作成。
そして公式のリファレンスを参考に、プロジェクトルートで以下コマンドを実行。

npx create-react-app frontend

するとfrontend配下にpublicsrcなどのディレクトリが作られました。

2. 静的ファイルの移動、作成

Laravelのpublic/の中身をfrontend/public/へ移管します。
あとfrontend/.env.exampleもこのタイミングで作っておきます。

3. 動作検証 その1 ルーティング

ここで一旦簡単な動作検証を挟みます。
/testにアクセスして開く画面、Test.jsfrontend/srcに作成します。

frontend/src/Test.js

const Test = () => {

  return (
    <>
      <p>これはテストです。</p>
    </>
  );
}

export default Test;

次にルーティング部分を作ります。react-router-domを以下のコマンドでインストールします。

npm install react-router-dom

react-router-domを使ってルーティングを定義します。index.js、App.jsの中身を以下のように書き換えます。

frontend/src/index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter as Router } from 'react-router-dom'; // 追加

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    // 追加: <App>を<Router>タグで囲む
    <Router>
      <App />
    </Router>
  </React.StrictMode>,
  document.getElementById('root')
);

frontend/src/App.js

import Test from './Test';
import './App.scss';
import { Routes, Route } from 'react-router-dom';

const App = () => {
  return (
    <div>
      // <Routes>タグを定義し、<Route>にルーティングを定義する
      <Routes>
        <Route path="/test" element={<Test />} />
      </Routes>
    </div>
  );
}

ここまでできたらnpm startを実行し、http://localhost:3000/testにアクセスしてみます。「これはテストです。」とだけ書かれた画面が表示されたらOK。

4. 動作検証 その2 API連携

続いてTest.jsを使ってAPI連携を試します。
まずはbladeを使っていたbackendのControllerを、以下のように修正します(Postの中身については割愛)。

app/Http/Controllers/PostController.php

<?php
namespace App\Http\Controllers;

use App\Models\Post;
use Carbon\CarbonImmutable;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::get();
        $response = [
            'posts' => $posts,
        ];

        // 修正前: return response()->view('index', $response);
        return response()->json($response);
    }
}

routes/api.php

Route::get('/posts', 'PostController@index'); // 追記

場合によってはphp artisan route:clearが必要かもしれません。その辺は適宜実行で。

ここまでできたらAPI側は改修済みなので、frontend側にAPIコールを書いて疎通確認をしてみます。

frontend/src/Test.js

import React, { useEffect, useState } from "react";
import axios from "axios";

const Test = () => {

  const [posts, setPosts] = useState([]);

  // 先ほど作成したLaravelのAPIのURL
  const url = "http://localhost:8000/api/posts";

  useEffect(() => {
    (async () => {
      try {
        const res = await axios.get(url);
        setPosts(res.data.posts);
        return;
      } catch (e) {
        return e;
      }
    })();
  }, []);

  return (
    <>
      {posts.map((post)=> {
        return (
          <div key={post.id}>
            <h1>{post.title}</h1>
            <p>{post.content}</p>
          </div>
        );
      })}
    </>
  );
}

export default Test;

ここまで書いたら再びhttp://localhost:3000/testにアクセスしてみます。
Postテーブルのレコード一覧のタイトルと内容が列挙されていたらこれでOKです。

内容が長くなったので今回はこの辺で。続きは次回書きます。

Discussion