WordPress へようこそ。こちらは最初の投稿です。編集または削除し、コンテンツ作成を始めてください。
ブログ
-
【MW WPForm終了対策】Contact Form 7で完了ページにリダイレクトする方法【公式推奨】
MW WPFormの開発終了に伴い、フォームの再構築を余儀なくされている制作現場が増えています。
特に多いのが、Contact Form 7(以下CF7)に移行したものの、- 完了ページへ遷移できない
- JavaScriptで無理やり対応している
- 有料アドオンに頼るしかない?
というケース。
ですが、実はCF7公式が紹介している方法で、無料かつ簡潔に完了ページ遷移が可能なんです。
結論:JavaScriptと
functions.phpで完了ページ遷移はできる公式ドキュメント(CF7公式リンク)では、次のようなJavaScriptイベントを使う方法が紹介されています。
document.addEventListener( 'wpcf7mailsent', function( event ) {
location.href = '/thanks/';
}, false );ただし、
footer.phpなどに直書きするのではなく、WordPressのfunctions.phpに記述して管理するのがベストです。
実装手順(functions.phpで対応)
以下のコードを、子テーマの
functions.phpファイルに追記してください。add_action( 'wp_footer', function() {
?>
<script>
document.addEventListener( 'wpcf7mailsent', function( event ) {
location.href = '/thanks/'; // 任意の完了ページURLに変更
}, false );
</script>
<?php
});
ポイント解説
wpcf7mailsent:送信成功時に発火する公式イベントlocation.href = '/thanks/';:送信後の遷移先wp_footer:WordPressのフッター領域にスクリプトを挿入するフック
注意点
- JavaScriptが無効な環境では動作しません(稀)
- 完了ページ
/thanks/は事前に作成しておく必要があります - 複数フォームがある場合は
event.detail.contactFormIdを条件に含めて制御できます
例:
if (event.detail.contactFormId == '123') {
location.href = '/thanks/';
}
補足:Contact Form 7 で完了ページを使うメリット
- GAやCVタグの設置が可能(完了ページでトラッキングしやすい)
- 送信後に安心感を与える導線が作れる
- 静的なthanks.htmlなどにも遷移できる
まとめ
MW WPForm終了後、CF7への移行は王道ですが「完了ページが出せない」と悩む必要はありません。
公式の方法を活用すれば、プラグイン不要・コードのみで対応可能です。
関連リンク
お困りの方へ
制作会社様や担当者の方で「実装が不安」「ついでにフォーム全体を整理したい」という方は、お気軽に[お問い合わせページ]からご相談ください。
-
Laravel(バックエンド) + Next.js(フロントエンド)の構成例
API通信編ではjson-serverにてバックエンドを構築しましたが、より実践的にバックエンドをLaravelを用いた場合の構成例と各種設定について説明します。
結論 → Laravel を API サーバーとして使い、Next.js でフロントエンドを構築する!
データのやり取りは REST API または GraphQL を利用!システム構成
Laravel(バックエンド)と Next.js(フロントエンド)は以下のように構成する!
my-project/ ├── backend/ ← Laravel(API サーバー) ├── frontend/ ← Next.js(フロントエンド)Laravel のセットアップ
Laravel プロジェクト作成
composer create-project --prefer-dist laravel/laravel backendLaravel のプロジェクトフォルダが
backend/に作成される!環境変数を設定(
.env).envファイルの設定APP_NAME=Laravel APP_ENV=local APP_KEY=base64:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx APP_DEBUG=true APP_URL=http://localhost:8000 DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=mydatabase DB_USERNAME=root DB_PASSWORD=環境に合わせて
DB_*の設定を変更!API の CORS(クロスオリジン)設定
backend/app/Http/Middleware/VerifyCsrfToken.phpのexceptにapi/*を追加protected $except = [ 'api/*' ];CORS を許可するために
cors.phpを設定return [ 'paths' => ['api/*'], 'allowed_methods' => ['*'], 'allowed_origins' => ['http://localhost:3000'], // Next.js のURL 'allowed_headers' => ['*'], 'supports_credentials' => true, ];フロントエンド(Next.js)からのリクエストを許可する!
Laravel API のエンドポイント作成
API ルート(
backend/routes/api.php)use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use App\Http\Controllers\UserController; Route::get('/users', [UserController::class, 'index']);UserController.phpを作成namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\User; class UserController extends Controller { public function index() { return response()->json(User::all()); } }API で
GET /api/usersにアクセスすると、ユーザー一覧が取得できる!Laravel のサーバーを起動
php artisan serve --host=127.0.0.1 --port=8000API サーバーが
http://127.0.0.1:8000で動作する!
これで Laravel 側の準備は完了!Next.js のセットアップ
Next.js プロジェクト作成
npx create-next-app@latest frontendfrontend/に Next.js のプロジェクトが作成される!API の取得を実装(フロントエンド)
frontend/app/page.tsxに API 通信を追加"use client"; import { useEffect, useState } from "react"; export default function Home() { const [users, setUsers] = useState<{ id: number; name: string }[]>([]); useEffect(() => { fetch("http://127.0.0.1:8000/api/users") // Laravel の API .then((res) => res.json()) .then((data) => setUsers(data)); }, []); return ( <div> <h1>ユーザー一覧</h1> <ul> {users.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> </div> ); }Next.js から Laravel API (
http://127.0.0.1:8000/api/users) にアクセス!
取得したユーザー一覧を画面に表示!Next.js のサーバーを起動
cd frontend npm run devhttp://localhost:3000で Next.js が動作!
フロントエンド + バックエンドの連携完了!本番環境用のコマンド
本番用にビルド
npm run buildここでエラーが出るとエラー内容に応じて修正が必要になります。
buildができたら本番サーバーを起動します。
npm run startこれで本番環境の設定は完了です。
実際のアプリではWebサーバーの構築をnginxなどで行い、confファイルで各URLの役割を設定することで公開することになります。
-
TypeScriptその③
useStateの型宣言
useStateの型宣言は下記にようにします。
const [count, setCount] = useState<number>(0);
API のレスポンス型宣言
APIのレスポンスで受け取った値の型宣言は下記のようにします。
type User = { id: number; name: string; email: string; }; async function fetchUser(): Promise<User> { const response = await fetch("https://example.com/api/user/1"); return response.json(); // `User` 型のデータが返ることを期待 }
このようにPromiseオブジェクト(非同期処理の結果を受け取るためのオブジェクト)にくっつける形で定義します。
ただ、API データ取得関数は色々なデータを受け取る想定で使い回すことが多いので、その場合は型を後から決める仕組み「ジェネリクス」を使用することがあります。
async function fetchData<T>(url: string): Promise<T> { const response = await fetch(url); return response.json(); } // `User` 型のデータを取得 fetchData<User>("https://example.com/api/user").then((user) => { console.log(user.name); }); // `Post` 型のデータを取得 fetchData<Post>("https://example.com/api/post").then((post) => { console.log(post.title); });
このようにレスポンスの型をどんなデータでも扱えるようにすることで、関数の使い回しができます。
また、fetchData<T>と関数名の後にもジェネリクスをつけていますが、これは「ジェネリクス(
T)を使う関数を作る」という意味合いでPromise<T>とセットになっています。 -
TypeScriptその②
配列の型宣言
配列の場合の書き方
const numbers: number[] = [1, 2, 3, 4, 5];const numbers: Array<number> = [1, 2, 3, 4, 5];どちらも同じ意味となります。

オブジェクトの型宣言
オブジェクトの型宣言は下記のように書きます。
const user: { name: string; age: number } = { name: "田中", age: 30 };このように、キー毎に型を定義します。
オブジェクトの場合、「type」を使うと見た目をスッキリすることもできます。
type User = { name: string; age: number; }; const user: User = { name: "田中", age: 30 };
オブジェクトの配列の型宣言
オブジェクトが配列になっているデータを扱うことが多いです。
その場合の書き方は以下です。
const users: { id: number; name: string }[] = [ { id: 1, name: "田中" }, { id: 2, name: "佐藤" } ];「type」を使えばスッキリかけます。
type User = { id: number; name: string; }; const users: User[] = [ { id: 1, name: "田中" }, { id: 2, name: "佐藤" } ];
このようにオブジェクトの型宣言をする際は「type」を使うと分かりやすくなります。
propsの型宣言
propsで受け取る値の型を定義できます。
type GreetingProps = { name: string; age: number; }; function Greeting({ name, age }: GreetingProps) { console.log(`こんにちは、${name} (${age}歳)!`); }
渡ってきたpropsはオブジェクトになっているので、このように書くことでpropsの型宣言ができます。
関数の型宣言
関数では引数と戻り値にそれぞれ型宣言できます。
type User = { id: number; name: string; email: string; }; function getUserName(user: User): string { return user.name; }
-
TypeScriptその①
本章ではTypeScriptを学習します。実際にNext.jsのプロジェクトはTypeScriptで記述されることが多いので、習得しましょう。
TypeScriptとは?
TypeScriptとは、データの型を指定できるJavascriptです。

Javascriptではデータの型は設定した値によって自動的に決まり、変更するときに異なる型のデータを入れることができますが、TypeScriptは宣言時に型を指定することで、指定した型しか扱えないようにできます。

このように宣言時に型を指定する言語を「静的型付け言語」、入れる値によって自動的に型が決まる言語を「動的型付け言語」と呼びます。
TypeScript(静的型付け言語)のメリット
TypeScriptを使用するメリットは下記です。
- 間違った型のデータを入れると、実行前にエラーが出る → エラーを事前に発見できる
- チームで開発するとき、どんなデータが使われるのか一目でわかる → 保守しやすい
- エディタの補完機能が強化され、ミスが減る → 開発のスピードアップ
特にチームで開発する際や大規模な開発に適しているので、企業で採用されています。
Next.js + TypeScript
では実際にNext.jsで使用してみましょう。
まずはプロジェクトを作成します。
npx create-next-app@latest my-ts-appTypeScriptを使用するか聞かれるので「Yes」を選択してください。

作成しました。

このようにファイル名が「tsx」や「ts」になっています。
基本的な使い方はJavascript版と同じです。
page.tsxを編集してみます。
app/page.tsx
export default function Home() { let hello: string = "hello,world!"; hello = 5; return ( <> <h1>{hello}</h1> </> ); }
このように、変数helloに数値を入れようとするとエラーになります。
このように別の型の値を入れようとした段階でエラーが出るので、アプリが組み上がってきた段階で予期せぬエラーが起こりにくくなるわけです。
-
fetchを使ったAPI通信(Next.js)その⑤
Delete(データ削除)
app/components/DeleteDog.js
"use client"; export default function DeleteDog({ dogs, setDogs }) { const deleteDog = async (id) => { const response = await fetch(`http://localhost:3001/dogs/${id}`, { method: "DELETE" }); if (response.ok) { setDogs(dogs.filter((dog) => dog.id !== id)); } }; return ( <div> <h2>🐕 犬を削除</h2> {dogs.map((dog) => ( <button key={dog.id} onClick={() => deleteDog(dog.id)}> {dog.name}({dog.age}歳)削除 </button> ))} </div> ); }
コード解説
DeleteDogコンポーネントを定義export default function DeleteDog({ dogs, setDogs }) {✅
DeleteDogという React コンポーネントを作成
✅dogs(犬のリスト)とsetDogs(犬のリストを更新する関数)をpropsとして受け取るpropsの受け取り方ですが、今回は「分割代入」を使用して受け取っています。
分割代入ってなに?
💡 「オブジェクトや配列の中から、特定の値を簡単に取り出せる魔法の書き方」
💡 「データの中から必要な部分だけをサクッと使う方法」
propsも複数渡ってくるときはオブジェクトとして扱うので、{ dogs, setDogs }という受け取り方ができます。
deleteDog関数を定義const deleteDog = async (id) => {✅
id(削除したい犬のid)を受け取る関数を作成
✅awaitを使ってfetchでデータを削除するため、asyncをつけるfetchでDELETEリクエストを送るconst response = await fetch(`http://localhost:3001/dogs/${id}`, { method: "DELETE" });✅
fetch()を使ってjson-serverのDELETEAPI を呼び出し
✅http://localhost:3001/dogs/${id}にDELETEリクエストを送る
✅idのワンちゃんをデータベース(db.json)から削除するここでresponseが受け取る値はjson-serverデフォルトのものですが、通常はバックエンドアプリ側で設定した戻り値となります。
if (response.ok)で削除成功かチェックif (response.ok) {✅ サーバーが「削除成功!」と返したら
trueになる
✅ もし削除に失敗したらfalseになり、リストの更新をしないsetDogs()で削除したワンちゃんを画面から消すsetDogs(dogs.filter((dog) => dog.id !== id));✅ 削除した
id以外のワンちゃんだけ残す(削除したidのワンちゃんを削除)
✅ 新しい配列をsetDogsでdogsに設定ここでは「filter()」メソッドを使用しています。
filter()とは?💡 リストの中から、特定の条件に合うものだけを選び出す魔法のメソッド
💡 あるものの中から不要なものを捨てて、必要なものだけを残した新しい配列を作成する
dogs.map((dog) => (...)で犬ごとにボタンを作る{dogs.map((dog) => (✅
dogsのリストをmap()で1匹ずつ取り出す
✅ ワンちゃんごとに「削除ボタン」を作成ボタンにクリックイベント(deleteDog関数)設定
<button key={dog.id} onClick={() => deleteDog(dog.id)}>✅ ボタンを押すと、その犬の
idをdeleteDog()に渡す
✅ これでDELETEリクエストが実行され、ワンちゃんが削除される起動
まずjsonサーバーを起動します。
npx json-server --watch db.json --port 3001次に別のターミナルを開いて開発サーバーを起動します。
npm run devこのような画面が表示され、犬の「追加(C)表示(R)更新(U)削除(D)」ができれば成功です。

まとめ
今回でAPI通信を使ったCRUDの実装は終わりです。一般的なアプリに必要な基本的な機能を実装しました。
複雑に見えますが、書き方を覚えて使ってみることで、理解が深まるので是非練習してみてください。
-
fetchを使ったAPI通信(Next.js)その④
データ更新(Update)
app/components/UpdateDog.js
"use client"; import { useState } from "react"; export default function UpdateDog(props) { const [updatedValues, setUpdatedValues] = useState({}); // 名前&年齢の変更用ステート // ✅ 名前・年齢の入力変更を管理する関数 const handleInputChange = (id, field, value) => { setUpdatedValues({ ...updatedValues, [id]: { ...updatedValues[id], [field]: value } }); }; // ✅ 名前&年齢をまとめて更新 const updateDogInfo = async (id) => { const currentDog = props.dogs.find((dog) => dog.id === id); const newData = { name: updatedValues[id]?.name ?? currentDog.name, // 入力がなければ元の値 age: updatedValues[id]?.age ? Number(updatedValues[id].age) : currentDog.age // 入力がなければ元の値 }; const response = await fetch(`http://localhost:3001/dogs/${id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(newData) }); if (response.ok) { props.setDogs( props.dogs.map((dog) => (dog.id === id ? { ...dog, ...newData } : dog)) ); } }; return ( <div> <h2>🐕 犬の情報を更新</h2> {props.dogs.map((dog) => ( <div key={dog.id}> {/* 名前の入力欄 */} <input type="text" value={updatedValues[dog.id]?.name ?? dog.name} onChange={(e) => handleInputChange(dog.id, "name", e.target.value)} /> {/* 年齢の入力欄 */} <input type="number" value={updatedValues[dog.id]?.age ?? dog.age} onChange={(e) => handleInputChange(dog.id, "age", e.target.value)} /> {/* 更新ボタン(1回の通信で名前&年齢を変更) */} <button onClick={() => updateDogInfo(dog.id)}>更新</button> </div> ))} </div> ); }
コード解説
state設定
const [updatedValues, setUpdatedValues] = useState({});✅ 犬の名前と年齢の変更を一時的に保存するための状態管理のためのstate
実際の
updatedValuesの中身(例){ "1": { "name": "ゴールデンレトリバー", "age": 5 }, "2": { "name": "柴犬", "age": 3 } }📌 このように
idをキーとして、nameとageを管理handleInputChange(名前・年齢の入力変更を管理する関数)const handleInputChange = (id, field, value) => { setUpdatedValues({ ...updatedValues, [id]: { ...updatedValues[id], [field]: value } }); };✅ ユーザーが入力した値を
updatedValuesに保存
✅ スプレッド構文...updatedValuesで、元のupdatedValuesの内容を維持
✅ 新しいidのデータを{ ...updatedValues[id], [field]: value }でスプレッド構文を使って更新updateDogInfo(API通信する関数)
const updateDogInfo = async (id) => {「id」を引数とする「更新」ボタンをクリックしたときのイベントハンドラでAPI通信します。
currentDogにidに一致する犬の情報を取得const currentDog = props.dogs.find((dog) => dog.id === id);find関数の説明

親コンポーネントから渡ってきたprops.dogsの中で「id」が合致する犬の要素を抽出しています。
更新するデータ
newDataを作成const newData = { name: updatedValues[id]?.name ?? currentDog.name, age: updatedValues[id]?.age ? Number(updatedValues[id].age) : currentDog.age };name: updatedValues[id]?.name ?? currentDog.name
✅
?.(オプショナルチェーン)を使い、入力がない場合は undefinedを返すように。
✅??(Nullish Coalescing)を使い、undefinedのときに初期値(currentDog.name)を設定しているage: updatedValues[id]?.age ? Number(updatedValues[id].age) : currentDog.age
✅
?.(オプショナルチェーン)を使い、入力がない場合は undefinedを返すように。✅? : 三項演算子を使い、
undefinedのときに初期値(currentDog.age)を設定PUTでサーバーに送信const response = await fetch(`http://localhost:3001/dogs/${id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(newData) });✅
fetchでjson-serverにデータを送る
✅method: "PUT"により、${id}で指定したデータの既存データを上書き
✅JSON.stringify(newData)でnewDataをJSON形式に変換ここの処理はjson-server規定の動きに準じています。
実際はバックエンドアプリのルーティングに沿ってアクセスしたURLごとに処理が動き、その返り値が返ってくることになります。
props.setDogsでstateを更新if (response.ok) { props.setDogs( props.dogs.map((dog) => (dog.id === id ? { ...dog, ...newData } : dog)) ); }response.okがtrueだったときに、props.setDogsの更新用関数を使ってprops.dogsを更新しています。
mapの処理で三項演算子を使い、指定idの犬の場合は内容を更新し、それ以外はもともとの犬の入った新しいdogsを作り、setDogsで更新しています。

例えばスプレッド構文を使わずに下記のように書くと同じようにnameとageとキーの値を更新できます。
{ ...dog, "name": "柴犬", "age": 5}JSX
最後に戻り値として返すJSXです。
return ( <div> <h2>🐕 犬の情報を更新</h2> {props.dogs.map((dog) => ( <div key={dog.id}> {/* 名前の入力欄 */} <input type="text" value={updatedValues[dog.id]?.name ?? dog.name} onChange={(e) => handleInputChange(dog.id, "name", e.target.value)} /> {/* 年齢の入力欄 */} <input type="number" value={updatedValues[dog.id]?.age ?? dog.age} onChange={(e) => handleInputChange(dog.id, "age", e.target.value)} /> {/* 更新ボタン(1回の通信で名前&年齢を変更) */} <button onClick={() => updateDogInfo(dog.id)}>更新</button> </div> ))} </div> );mapメソッド
{props.dogs.map((dog) => (props.dogsをmapで処理しそれぞれの入力用リストを作成します。
✅
props.dogsのリストをmap()で1匹ずつ取り出す
✅dogに1匹ずつデータが入るリストのタグ
<div key={dog.id}>✅
<div>で各犬の情報を囲む!
✅key={dog.id}を入れることで、React がどの犬かわかるようにする(リストの必須ルール)名前の入力欄(
<input>)を作る<input type="text" value={updatedValues[dog.id]?.name ?? dog.name} onChange={(e) => handleInputChange(dog.id, "name", e.target.value)} />✅ 名前を入力するための
<input>(テキストボックス)を作成属性 意味 type=”text” 文字を入力できるテキストボックス value={updatedValues[dog.id]?.name ?? dog.name} 入力値の管理(もし updatedValuesに新しい名前があればそれを表示、なければdog.nameを表示)onChange={(e) => handleInputChange(dog.id, “name”, e.target.value)} 入力が変わったら handleInputChange()を実行して、updatedValuesに保存ここでも「?」オプショナルチェーンと「??」Nullish Coalescingを使ってupdateValuesの値がない場合は元々の値を初期値として表示されるようにしています。
年齢の入力欄(
<input>)を作る同じく年齢ようの入力欄も作ります。
<input type="number" value={updatedValues[dog.id]?.age ?? dog.age} onChange={(e) => handleInputChange(dog.id, "age", e.target.value)} />✅ 名前と同じように、年齢も入力できる
属性 意味 type=”number” 数字だけ入力できるボックス value={updatedValues[dog.id]?.age ?? dog.age} 新しく入力された ageがあればそれを表示、なければdog.ageを表示onChange={(e) => handleInputChange(dog.id, “age”, e.target.value)} 入力が変わったら handleInputChange()を実行して、updatedValuesに保存更新ボタンを作る
<button onClick={() => updateDogInfo(dog.id)}>更新</button>✅ 「更新」ボタンを押すと
updateDogInfo(dog.id)が実行される
✅ これでPUTリクエストが送られ、サーバーのデータが更新されるまとめ
以上がデータ更新のコンポーネントでした。色々な書き方が出てきて複雑に感じるかと思いますが、まずは何をやっているのか理解できるように咀嚼してみてください。
-
fetchを使ったAPI通信(Next.js)その③
データ追加(Create)
app/components/CreatDog.js
"use client"; import { useState } from "react"; export default function CreateDog(props) { const [newDog, setNewDog] = useState({ name: "", age: 0 }); const addDog = async () => { const newEntry = { name: newDog.name, age: newDog.age }; const response = await fetch("http://localhost:3001/dogs", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(newEntry) }); if (response.ok) { const addedDog = await response.json(); // `json-server` が追加したデータを返す props.setDogs([...props.dogs, addedDog]); setNewDog({ name: "", age: 0 }); } }; return ( <div> <h2>🐕 新しい犬を追加</h2> <input type="text" placeholder="名前" value={newDog.name} onChange={(e) => setNewDog({ ...newDog, name: e.target.value })} /> <input type="number" placeholder="年齢" value={newDog.age} onChange={(e) => setNewDog({ ...newDog, age: Number(e.target.value) })} /> <button onClick={addDog}>追加</button> </div> ); }
コード解説
const [newDog, setNewDog] = useState({ name: "", age: 0 });入力フォーム用のstateを設定します。
addDog(API通信)処理
「追加」ボタンをクリックしたときのイベントハンドラー「addDog」によるAPI通信の処理を見ていきます。
const addDog = async () => { const newEntry = { name: newDog.name, age: newDog.age }; const response = await fetch("http://localhost:3001/dogs", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(newEntry) }); if (response.ok) { const addedDog = await response.json(); props.setDogs([...props.dogs, addedDog]); setNewDog({ name: "", age: 0 }); } };1行ずつ説明していきます。
const addDog = async () => {✅ これは関数の定義
👉const addDogは 関数を変数addDogに代入している
👉async () =>は 「この関数は非同期処理を行う」 という宣言💡 「非同期処理って何?」
→ サーバーと通信するとき、データが返ってくるまで待つ必要がある
→ その間に他の処理を進められるのが「非同期」
→ この関数はawaitを使うためにasyncをつける
const newEntry = { name: newDog.name, age: newDog.age };✅ 新しい犬のデータをオブジェクトで作る
👉{}は オブジェクト(データのまとまり)を作る記号
👉name: newDog.nameは、newDog.nameの値をnameというキーに入れる
👉age: newDog.ageも同じ💡 「
newDog.nameって何?」
→ これは React のuseStateで管理されているnewDogのnameの値
→ つまりnewDogに入力したnameとageをnewEntryに入れてるconst response = await fetch("http://localhost:3001/dogs", {✅ サーバー(
json-server)にデータを送る
👉fetch("URL")は 指定したURLにデータを送ったり受け取ったりする関数
👉awaitをつけることで、データが返ってくるまで待つ💡 「
awaitをつけないとどうなる?」
→ データを待たずに次の処理が進んで、値がundefinedになったりバグるmethod: "POST",✅
POSTメソッドを使う
👉 HTTP には 4つの基本的なメソッド(動作)があるメソッド 何をする? GET データを取得(例:犬の一覧をもらう) POST データを追加(例:新しい犬を登録する) PUT データを更新(例:犬の年齢を変更する) DELETE データを削除(例:犬をリストから消す) 💡
POSTだから、新しい犬のデータを送る処理になるheaders: { "Content-Type": "application/json" },✅ 「このデータは
JSON形式だよ!」とサーバーに伝える
👉headersは、サーバーに送るデータの種類を指定する部分
👉"Content-Type": "application/json"は 「送るデータはJSON形式」と宣言するbody: JSON.stringify(newEntry)✅ データを
JSONに変換して送る
👉JSON.stringify(データ)は、JavaScript のオブジェクトをJSON文字列に変換する関数if (response.ok) {✅ サーバーが「成功!」と返したら実行
👉response.okは、通信が成功 (200番台のステータス) だったらtrueになる
👉 もしfalseだったら、何かエラーが起きたということ💡
response.okってどういう意味?
→ サーバーが「リクエスト成功!」と返したらtrueになる
→falseの場合はエラー(例:404 Not Foundや500 Server Error)const addedDog = await response.json();✅ サーバーから返ってきたデータを
JSONに変換
👉response.json()は、サーバーのレスポンスをJSON形式のデータに変換する関数
👉awaitをつけることで、データが変換されるまで待つ💡 「なぜ
response.json()が必要?」
→ サーバーから返ってくるデータはJSON形式の文字列だから、そのままじゃ使えない
→ だからresponse.json()で JavaScript のオブジェクトに変換するprops.setDogs([...props.dogs, addedDog]);✅ React の
stateを更新して、新しい犬を追加
👉props.setDogs()は、親コンポーネントのdogsを更新する関数
👉[...props.dogs, addedDog]は、現在のdogs配列にaddedDogを追加する💡 なぜ
...props.dogs(スプレッド構文)を使うの?
→ React のstate(props.dogs)は、直接変更できない
→ だから、新しい配列[...]を作って、更新するsetNewDog({ name: "", age: 0 });✅ 入力フォームをリセット!
👉setNewDog({ name: "", age: 0 })は、新しい犬の情報を 空にする!
👉 次に入力するときに、前回のデータが残らないようにする!💡 「
setNewDogとは?」
→useStateで管理しているnewDogを更新する関数!
→ フォームの中身をリセットするために使う!🐵
addDogの処理の流れ1️⃣
newEntryを作る(新しい犬の情報)
2️⃣fetchでサーバーにデータを送る(POSTリクエスト)
3️⃣ サーバーが処理してresponseを返す
4️⃣response.okなら、データをJSONに変換
5️⃣props.setDogs([...props.dogs, addedDog])でstateを更新
6️⃣setNewDog({ name: "", age: 0 })でフォームをリセット入力フォームで入力された情報をサーバーに送ってデータベースを更新し、通信がOKであれば、ページで表示されている一覧の内容も更新するという流れの処理です。
responseでサーバーから返ってくるデータの内容は実際はバックエンド側のアプリでPOSTに対して何をreturnするかの記述に依存します。今回は、
👉
json-serverでPOSTリクエストを送ると、デフォルトで 送られたデータにidを追加して返す仕様に準じています。JSX
return ( <div> <h2>🐕 新しい犬を追加</h2> <input type="text" placeholder="名前" value={newDog.name} onChange={(e) => setNewDog({ ...newDog, name: e.target.value })} /> <input type="number" placeholder="年齢" value={newDog.age} onChange={(e) => setNewDog({ ...newDog, age: Number(e.target.value) })} /> <button onClick={addDog}>追加</button> </div> );inputタグの入力フォームでそれぞれnewDogのnameとageをsetNewDog更新用関数を使って更新しています。ここでも、stateの値そのものを変更はできないので、スプレッド構文を使ってそれぞれのキーの値を更新する記述をしています。
onChange={(e) => setNewDog({ ...newDog, name: e.target.value })} onChange={(e) => setNewDog({ ...newDog, age: Number(e.target.value) })}「age」を更新するinputタグでは念の為Number()を使って入力された値を数値に変換しています。
全体体に少し複雑に見えますが、すべてを理解するというよりは「書き方を覚える」というスタンスでOKです。
-
fetchを使ったAPI通信(Next.js)その②
データ取得(Read)
app/components/ReadDogs.js
"use client"; import { useEffect } from "react"; export default function ReadDogs(props) { // ✅ props から `dogs` を受け取る useEffect(() => { fetch("/dogs.json") .then((res) => res.json()) .then((data) => props.setDogs(data)) // ✅ `page.js` の `dogs` を直接更新 .catch((error) => console.error("エラー:", error)); }, []); return ( <div> <h1>🐶 犬のリスト</h1> <ul> {props.dogs.map((dog) => ( // ✅ `dogs` は `page.js` の `state` を使用 <li key={dog.id}>{dog.name}({dog.age}歳)</li> ))} </ul> </div> ); }
コード解説
useEffect(() => { fetch("http://localhost:3001/dogs") .then((res) => res.json()) .then((data) => props.setDogs(data)) .catch((error) => console.error("エラー:", error)); }, []);useEffectの処理でfetch関数を使って「/dogs.json」からデータを受け取っています。

fetch("http://localhost:3001/dogs")取得先のURLを指定しています。
.then((res) => res.json())受け取ったレスポンス情報をJSONデータに変換しています。
.then((data) => props.setDogs(data))JSONデータをdogsのstateに設定しています。
.catch((error) => console.error("エラー:", error));API通信が何らかの理由でうまくいかなかった際にエラー内容をログ出力する処理を記述しています。
次にJSXでは、
{props.dogs.map((dog) => ( <li key={dog.id}>{dog.name}({dog.age}歳)</li> ))}「dogs」配列をmapメソッドを使ってリスト表示しています。