Laravel(+Docker)でReactを試す

はじめに

試しにLaravel+Reactのプロジェクトを作ってみました。

※8/1追記

Docker環境で試してみたので大幅追記しました。
ちなみにReduxやTypeScriptはLaravel環境下でインストールできませんでした💦
こればっかりは別プロジェクトで切り分けて実装してコンパイルしたものを読み込ませるのがよさそうですね。。。

✅環境
Windows/XAMPP/MySQL

✅参考
📚Laravel実践開発

6.8の場合

※8/1追記。

初めてのLaravel6.xとReact入門

※Docker環境で実施しました。

✅セットアップ~カウンターコンポーネントの作成

laravel/uiをインストール(“1.x”を付けないと最新がインストールされ、Laravelのバージョン6と整合が取れない。)

$ composer require laravel/ui "1.x" --dev
$ php artisan ui react --auth
React scaffolding installed successfully.
$ npm install && npm run dev

webpack.mix.jsが書き換わる。

const mix = require('laravel-mix');

  mix.react('resources/js/app.js', 'public/js')
   .sass('resources/sass/app.scss', 'public/css');

welcome.blade.php

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>{{ config('app.name', 'Laravel') }}</title>
    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>
    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>

<body>
    <div id="counter"></div>
</body>
</html>

js/app.js

require('./bootstrap');
require('./components/Counter');

js/components/Counter.js

import React, {useState} from "react";
import ReactDOM from "react-dom";

const Counter = () => {
  const [count, setCount] = useState(0);
  const increment = () => {
    setCount(count + 1);
  };
  const decrement = () => {
    setCount(count - 1);
  };

  return (
    <>
        <p>useState Counter:{count}</p>
        <button onClick={increment}>+</button>
        <button onClick={decrement}>-</button>
    </>
  );
};

ReactDOM.render(<Counter />, document.getElementById("counter"));

※コントローラ周りも後ほど弄ったので若干コード変わってます

✅認証機能+Auth::userを非同期で取得

※div id=”app”はlayouts/app.blade.phpでがっつり使われているのでReactをマウントする際のidに要注意!!

ユーザーテーブル作成

$ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.12 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table     
Migrated:  2014_10_12_100000_create_password_resets_table (0.14 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.06 seconds)

※localhost/registerからユーザーデータを作成

ログインデータをReact側(axios)で取得してみる。

HomeController.php

use Illuminate\Support\Facades\Auth; // 認証情報
~~~~
public function json(){
  return Auth::user()->toJson();
}

web.php

Route::get('/json', 'HomeController@json');

http://localhost/jsonにアクセスして確認。

import React, {useState} from "react";
import ReactDOM from "react-dom";

const Counter = () => {
  const [data, setData] = useState({
    id:"none",
    name:"none"
  });
  const getAction = () => {
    axios.get("/json")
      .then(response => {
        setData(response.data)
      })
  }

  return (
    <>
      <p>ID:{data.id}</p>
      <p>User:{data.name}</p>
      <button onClick={getAction}>get</button>
    </>
  );
};

ReactDOM.render(<Counter />, document.getElementById("counter"));

✅User::allの取得

HomeController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User; // Userモデルクラス
use Illuminate\Support\Facades\Auth; // 認証情報

class HomeController extends Controller
{
    public function __construct()
    {
      $this->middleware('auth');
    }
    public function index()
    {
      $msg = "Docker × Laravel × React";
      $user = Auth::user();
      return view('welcome',compact("msg","user"));
    }
    public function json(){
      return User::all()->toJson();
    }
}

welcome.blade.php

<div class="card">  
  <div class="card-header">
    {{ $msg }} ログイン:{{ $user->name }}
  </div>
  <div className="card-body">
    <div id="user"></div>
  </div>
</div>

User.js

import React, {useState} from "react";
import ReactDOM from "react-dom";

const User = () => {
  const [data, setData] = useState([]);
  const getAction = () => {
    axios.get("/json")
      .then(response => {
        setData(response.data)
      })
  }
  return (
    <>
      {data.map(data => {
        return (
          <p>user{data.id}:{data.name}</p>
        )
      })}
      <button onClick={getAction}>get</button>
    </>
  );
};

ReactDOM.render(<User />, document.getElementById("user"));

せっかくなので入力値を取得できるようにして見る。

web.php

Route::get('/json/{id}', 'HomeController@json');

HomeController.php

public function json($id = 0){
  if($id == 0 ){
    return User::all()->toJson();
  }else{
    return User::find($id)->toJson();
  }
}

User.js

import React, {useState} from "react";
import ReactDOM from "react-dom";

const User = () => {
  const [users, setUsers] = useState([]);
  const [user, setUser] = useState({
  });
  const getAllAction = () => {
    axios.get("/json")
      .then(response => {
        setUsers(response.data)
      })
  }
  const getSelectAction = () => {
    let url = document.getElementById("select_num").value;
    axios.get("/json/"+ url)
      .then(response => {
        setUser(response.data)
      })
  }

  return (
    <>
      <p>ユーザー一覧</p>
      {users.map(data => {
        return (
          <p>user{data.id}:{data.name}</p>
          )
        })}
      <button onClick={getAllAction}>取得</button>
      <p>特定のユーザー</p>
      {user.id !== 0 &&
        <p>user{user.id}:{user.name}</p>
      }
      <div>
        <input type="number" id="select_num"></input>
      </div>
      <button onClick={getSelectAction}>取得</button>
    </>
  );
};

ReactDOM.render(<User />, document.getElementById("user"));

備忘録

以下、ホットリロードはDocker上でうまくいかず。mixにするとjsが読み込まれなかった。
※http://localhost/js/app.jsもしくはGoogle Consoleで確認可能

Laravel MixをつかってLaravelのUIをReactで書く

asset(“js/app.js”)だとHMRされない。mix(“js/app.js”)に書き換えてnpm run hot。

✅JSX内での条件分岐

【React知見】条件分岐(IF文)とそのネスト

✅Reduxを使う際はどうするのか??※失敗

以下、実装できなかったが、考えてみればLaravel側でDB使っているのであまりRedux使う必要性もないのかなと感じた。

パターン①Docker内でプロジェクト作成するもWebpackが競合して起動できず。。。

var/www# 
$ mkdir react-pj
$ cd react-pj
$ npx create-react-app . --typescript
$ yarn add axios // Laravelと違いデフォルトでは入っていないため
$ yarn start // error
  The react-scripts package provided by Create React App requires a dependency:
  "webpack": "4.42.0"
  Don't try to install it manually: your package manager does it automatically.
  However, a different version of webpack was detected higher up in the tree:
  /var/www/node_modules/webpack (version: 4.44.1)

パターン②Reduxだけインストールして使う※Sassと競合する。。。

$ npm i -D redux react-redux
$ npm audit fix --force

package.jsonに追記してみる。これまた失敗。

"redux": "^4.0.5",
"react-redux": "^7.2.0",

✅TypeScriptを入れてみる※失敗

$ npm i -D typescript @types/node @types/react @types/react-dom
npm ERR! File exists: C:\mydev\docker\laravel6.8_react\laravel\node_modules\.bin\sass
npm ERR! Remove the existing file and try again, or run npm
npm ERR! with --force to overwrite files recklessly.

👆どうやらSassと競合するらしい。。。–forceオプション使っても変わらず。。。

✅CORS問題

ローカル側(異なるポート番号)からためしにAPIを叩いてみるとCORS問題で突破できず。。。

axios.get("http://localhost/json")
  .then(response => {
    setUsers(response.data)
  })
}

Access to XMLHttpRequest at ‘http://localhost/json’ from origin ‘http://localhost:3002’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

 

npm からの移行 どうやらyarnもnpmも共存はできるっぽい。

余談

※以下記載の5.8と同じ方法でもローカル環境下では問題なく作れました。ですが、Docker環境下ではうまくいかず。。。

5.8の場合

※書籍のバージョンが5.8なのでまずは5.8から構築していこうと思います。

✅Reactを使うまでの環境構築

①プロジェクト生成

composer create-project laravel/laravel laravel-react --prefer-dist "5.8.*"

②デフォルトではVue.jsがセットされているのでReactに変更

※package.jsonが変更される。

php artisan preset react

変更前

"vue": "^2.5.17"

変更後

"@babel/preset-react": "^7.0.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",

③パッケージのインストール

npm install

④プロジェクトのビルド

npm run dev

✅Reactコンポーネントの表示

①デフォルトで作られているコンポーネントの確認

resources/js/components/Exaple.js

import React, { Component } from "react";
import ReactDOM from "react-dom";

export default class Example extends Component {
    render() {
        return (
            <div className="container">
                <div className="row justify-content-center">
                    <div className="col-md-8">
                        <div className="card">
                            <div className="card-header">Example Component</div>
                            <div className="card-body">
                                I'm an example component!
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

if (document.getElementById("example")) {
    ReactDOM.render(<Example />, document.getElementById("example"));
}

app.jsの確認

require('./bootstrap');
require('./components/Example');

webpack.mix.jsの確認

const mix = require('laravel-mix');

mix.react('resources/js/app.js', 'public/js')
  .sass('resources/sass/app.scss', 'public/css');

🙄コンポーネントがapp.jsで読み込まれて、webpack.mix.jsでコンパイルされているのがわかります。

②resources/views/welcome.blade.phpの編集

※根こそぎ落としました。

<body>
  <h1>Laravel</h1>
    <div id="example"></div>
    <script src="{{asset('/js/app.js')}}"></script>
</body>

③起動して確認

php artisan serve

http://127.0.0.1:8000/へアクセスして確認。

✅試しに関数型コンポーネント

Example.jsを編集

import React from "react";
import ReactDOM from "react-dom";

export default function Example(){ 
  return (
    <div className="container">
      <div className="row justify-content-center">
        <div className="col-md-8">
          <div className="card">
            <div className="card-header">Example Component</div>
            <div className="card-body">
                I'm an example component!※function
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

if (document.getElementById("example")) {
    ReactDOM.render(<Example />, document.getElementById("example"));
}

ビルド

npm run build

起動

php artisan serve

http://127.0.0.1:8000/へアクセスして確認

🙄関数型コンポーネントも問題なしですね!!

おわりに

割と簡単にReactのテンプレートを表示することができました◎

気が向いたら6.8でも試してみようと思いますが、5.8の方が構築が楽そう。

⇒どちらも特に難しさは変わらずでした。

非同期もVue.jsと同じくクリックイベントなりで発火されるaxios込みの関数を使えばできそうですし、できることは同じですね!

どちらのFWを選ぶかは好みになりそう。

💻Laravel5.7でReactを利用した開発をしてみる

👆これでToDoアプリ制作も面白そう。

💻LaravelでAPIを作成して、Reactで取得したい

こんなのもあった。

💻初めてのLaravel6.xとReact入門

バージョン6以降ならこれ参考になりそう。laravel/uiを使うらしい。

コメントを残す