はじめに
Laravel+Reactの練習にToDoアプリを作ってみます。
✅参考
☝️React側のメインの参考
☝️LaravelとReactの連携に
DB側セットアップ
環境構築は以下でやっています。
.envの編集
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3307 DB_DATABASE=todo DB_USERNAME=root DB_PASSWORD=
DB作成
mysql>create database todo; mysql>use todo;
マイグレーションファイル作成
$ php artisan make:migration create_todos_table --create=todos $ php artisan make:migration create_finished_todos_table --create=finished_todos
※テーブル名はスネークケースにすべしっぽい 参考
編集
※両方テーブル名以外同じ。
public function up() { Schema::create('todos', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->timestamps(); }); }
モデル作成(Tinkerでの検証やDB取得にモデルクラスが必要)
$ php artisan make:model Todo $ php artisan make:model FinishedTodo
※モデル名はアッパーキャメルにすること
テーブル作成実行
$ php artisan migrate
※以下MySQLコマンドで確認
MySQL [laravel_local]> show tables; +-------------------------+ | Tables_in_laravel_local | +-------------------------+ | failed_jobs | | finished_todos | | migrations | | password_resets | | todos | | users | +-------------------------+ 6 rows in set (0.003 sec)
シーダー作成
$ php artisan make:seeder TodosTableSeeder
$ php artisan make:seeder FinishedTodosTableSeeder
※アッパーキャメルにすること、単数複数の指定はない。
DatabaseSeeder.php
public function run() { $this->call(TodosTableSeeder::class); $this->call(FinishedTodosTableSeeder::class); }
TodosTableSeeder.php
※同じ要領でFinishedTodosTableSeeder.phpも編集
public function run() { for ($i = 1; $i <= 5; $i++) { DB::table('todos')->insert([ // finished_todos 'id' => $i, 'name' => "TODO".$i, // FINISHED TODO ]); } }
仮データ反映
$ composer dump-autoload // ファイルの読み込み $ php artisan db:seed Seeding: TodosTableSeeder Seeded: TodosTableSeeder (0.09 seconds) Seeding: FinishedTodosTableSeeder Seeded: FinishedTodosTableSeeder (0.02 seconds) Database seeding completed successfully. $ php artisan db:seed --class=TodosTableSeeder // 単発の場合
api.phpの編集
Route::get('/todos',function (Request $request) { $todos = App\Todo::all(); return response()->json(['todos' => $todos]); }); Route::get('/finished_todos',function (Request $request) { $finished_todos = App\FinishedTodo::all(); return response()->json(['finished_todos' => $finished_todos]); });
http://127.0.0.1:8000/api/todosにアクセスして確認

http://localhost/api/finished_todosにアクセス

React側セットアップ※DB表示まで
上記のJSONデータを取得できればOK
取得してみる。
import React, { useEffect, useState } from "react"; import axios from "axios"; function About() { const [todos, setTodos] = useState([]); const [finishedTodos, setFinishedTodos] = useState([]); useEffect(() => { getTodos(); getFinishedTodos(); }, []); const getTodos = async () => { const response = await axios.get("/api/todos"); setTodos(response.data.todos); }; const getFinishedTodos = async () => { const response = await axios.get("/api/finished_todos"); setFinishedTodos(response.data.finished_todos); }; return ( <div> <h1>Aboutページ</h1> <h2>Todo</h2> <ul> {todos.map(todo => ( <li key="{todo.id}">{todo.name}</li> ))} </ul> <h2>FinishedTodo</h2> <ul> {finishedTodos.map(todo => ( <li key="{todo.id}">{todo.name}</li> ))} </ul> </div> ); } export default About;
http://localhost/aboutで確認

DevToolsで検証
let response = await axios.get("/api/todos"); console.log(response.data); let response = await axios.get("/api/finished_todos"); console.log(response.data);

※上記画像命名規則修正前で若干古いです。
デザイン修正
インストール
npm i styled-components
about.css作成
body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; background-color: #fff2cc; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; }
about.js修正
import React, { useEffect, useState } from "react"; import './about.css'; import axios from "axios"; import styled from "styled-components"; function About() { const [todos, setTodos] = useState([]); const [finishedTodos, setFinishedTodos] = useState([]); useEffect(() => { getTodos(); getFinishedTodos(); }, []); const getTodos = async () => { const response = await axios.get("/api/todos"); setTodos(response.data.todos); }; const getFinishedTodos = async () => { const response = await axios.get("/api/finishedtodos"); setFinishedTodos(response.data.finishedtodos); }; return ( <div> <Title>Aboutページ</Title> <TodoContainer> <SubContainer> <SubTitle>Todo</SubTitle> <ul> {todos.map(todo => ( <li key="{todo.id}">{todo.name}</li> ))} </ul> </SubContainer> <SubContainer> <SubTitle>FinishedTodo</SubTitle> <ul> {finishedTodos.map(todo => ( <li key="{todo.id}">{todo.name}</li> ))} </ul> </SubContainer> </TodoContainer> </div> ); } const Title = styled.p` font-size: 26px; color: #0097a7; letter-spacing: 2.8px; font-weight: 200; `; const SubTitle = styled.p` font-size: 22px; color: #5c5c5c; `; const SubContainer = styled.div` width: 400px; `; const TodoContainer = styled.div` display: flex; flex-direction: row; width: 80%; margin: 0 auto; justify-content: space-between; `; export default About;
確認

だいぶそれっぽく?なりました◎
CRUD実装
以前Vue.jsで使った実装を参考にしていきます。
✅DB追加
React上で追加
const [input, setInput] = useState(""); const addTodo = () => { if (!!input) { setTodos([...todos,{ id:todos.length +1, name:input }]); setInput(""); } }; ---- // Titleタグ配下 <input onChange={e => setInput(e.target.value)} value={input} /> <button onClick={() => addTodo()}>追加</button>
確認

LaravelのDBに追加
api.phpにPOST送信用のルーティングを追加
Route::post('/todos',function (Request $request) { $todo = new App\Todo(); $todo->name = $request->name; $todo->save(); return response("OK", 200); });
js側、メソッドの修正
const addTodo = () => { if (!!input) { const data = { name: input } axios.post("/api/todos",data) .then(()=>{ console.log("DB追加"); getTodos(); setInput(""); }) } };

✅削除
api.phpに追記
Route::delete('/todos/{id}',function (Request $request, $id) { App\Todo::find($id)->delete(); return response("OK", 200);; });
JS側
const deleteTodo = id => { axios.delete("/api/todos/" + id).then(() => { console.log("DB削除") getTodos(); }); }; ~~~~ {todos.map(todo => ( <> <li id={todo.id}>{todo.name}</li> <button onClick={() => deleteTodo(todo.id)}> 削除 </button> </> ))}

※若干Warning出ているのが気になる。。。
Warning: Each child in a list should have a unique “key” prop.
✅状態の変更(更新)
ReactToDoのチュートリアルでは『完了済みにする』と『戻す』ボタンがある。
ここの処理をできるようにしたい。
備忘録
✅Laravelの命名規則

モデルをキャメルケースで書くとスネークケースに変換されるっぽい。
finishedTodo.php
クラス名をfinishedtodoに変更。
コメントを残す