LaravelとNext.jsを一緒に利用できるって知ってました?
LaravelはPHPのフレームワーク、Next.jsはReact(JavaScript)のフレームワークなので一緒に利用することはできないなんて思っていないですか?実はNext.jsとLaravelは一緒に利用できるんです。LaravelとNext.jsの同時利用の環境構築が簡単に行えるようにLaravel開発者がメンテナンスを行なっているLaravel Breeze Next.js Editionというものが存在します。Laravel Breeze Next.js EditionはGitHubにリポジトリが公開されているのでいつでも利用でき、公開されてから数年立ちますがNext.jsのアップデートに合わせて更新も行われています。Laravel Breeze Next.js Editionは認証機能も実装されており名前にBreezeが入っている通りLaravel Breezeが利用されています。
本文書はNext.jsとLaravelの2つの経験がある人または両方に興味がある人を対象にLaravel+Next.jsの環境構築の手順を公開しています。Laravel用に設定されてたNext.jsを利用するので手順はシンプルです。ぜひ興味がある人を利用してみてください。
Laravelを経験している人であればLaravel Breezeやフロントエンドという言葉を耳にするとInertiaやLivewireを利用しないといけないのかなと思う人もいるかもしれませんが今回の構成ではInertiaやLivewireは利用しません。
最新版のLaravel11でも利用することができ、Next.jsの最新版のバージョン14のapp Routerにも対応しています。
公開当時はLaravel9で動作確認を行いましたが最新版のLaravel11で動作確認を行い文書のリライトを行っています。
バックエンドの設定(Laravel)
LaravelはAPIを提供するバックエンドサーバとして設定します。
Laravelプロジェクトの作成
Laravelをインストールを行う前にNext.jsをインストールするフロントエンド用のディレクトリとバックエンド用のLaravelのディレクトリをわけるために任意の場所にlaravel-nexjsディレクトリを作成します。
laravel-nextjsディレクトリを作成後にlaravel-nextjsディレクトリに移動してcomposerコマンドを利用してLaravelプロジェクトの作成を行います。プロジェクト名にはlaravel-backendを指定しています。
% composer create-project laravel/laravel laravel-backend
Laravel11ではコマンドを実行するとSQLiteでデータベースの作成まで行ってくれるのでデータベースの設定は必要ありません。Laravel11より以前のバージョンを利用する場合はデータベースの作成やテーブルの作成を行う必要があります。
Breezeのインストール
プロジェクトの作成が完了するとlaravel-backendに移動してcomposeコマンドを利用してbreezeパッケージのインストールを行います。
% cd laravel-backend
% composer require laravel/breeze --dev
breezeのインストールが完了するとphp artisan breezeコマンドで利用できるようになります。
BreezeのAPI Stackのインストール
php artisan breeze:installコマンドのstackにapiを指定することでAPI用のScaffolding(骨組み)がインストールされます。その中にはSPA(Single Page Application)の認証に利用されるLaravel Sanctumが含まれています。
% php artisan breeze:install api
INFO Breeze scaffolding installed successfully.
Breezeのインストール後に.envファイルに環境変数のFRONTEND_URLが設定されます。APP_URLもhttp://localhostからhttp://localhost:8000に更新されます。
//略
APP_URL=http://localhost:8000
FRONTEND_URL=http://localhost:3000
//略
フロントエンドとバックエンドのオリジンが異なっていても通信が行えるようにCORS(Cross-Origin Resource Sharing)の設定も行われています。configフォルダのcors.phpファイルが作成され中身を確認すると.envファイルに設定したFRONTEND_URLがallowed_originsの配列に含まれていることが確認できます。
return [
/*
|--------------------------------------------------------------------------
| Cross-Origin Resource Sharing (CORS) Configuration
|--------------------------------------------------------------------------
|
| Here you may configure your settings for cross-origin resource sharing
| or "CORS". This determines what cross-origin operations may execute
| in web browsers. You are free to adjust these settings as needed.
|
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
*/
'paths' => ['*'],
'allowed_methods' => ['*'],
'allowed_origins' => [env('FRONTEND_URL', 'http://localhost:3000')],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];
web.phpファイルも更新されており、”/”にアクセスするとLaravelのバージョンが戻されます。
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return ['Laravel' => app()->version()];
});
require __DIR__.'/auth.php';
api.phpファイルも作成されルーティングの/userが設定されています。Laravel11ではデフォルトではapi.phpファイルは存在しません。
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::middleware(['auth:sanctum'])->get('/user', function (Request $request) {
return $request->user();
});
開発サーバの起動
php artisan serveコマンドを実行するとhttp://127.0.0.1:8000で開発サーバが起動します。
% php artisan serve
INFO Server running on [http://127.0.0.1:8000].
Press Ctrl+C to stop the server
ブラウザからhttp://127.0.0.1:8000にアクセスすると通常はLaravelの初期画面が表示されますがBreezeのstackをapiでインストールした場合はLaravelのバージョンがJSONで戻されます。ブラウザからアクセスするとLaravel11であることが確認できます。
フロントエンドの設定(Next.js)
フロントエンド側で利用するNext.jsのプロジェクトの作成を行います。Githubで公開されているbreeze-nextのリポジトリをcloneしてNext.jsの環境を作成します。breeze-nextリポジトリからインストールするNext.jsにはLaravel Sanctumによる認証機能が既に実装されています。
リポジトリのクローン
breeze-nextのリポジトリをクローンするためにgit cloneコマンドを実行します。別名にはnextjs-frontendという名前をつけています。コマンドはlaravel-nextjsディレクトリの下で行います。
% git clone https://github.com/laravel/breeze-next.git nextjs-frontend
Cloning into 'nextjs-frontend'...
remote: Enumerating objects: 110, done.
remote: Counting objects: 100% (25/25), done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 110 (delta 5), reused 14 (delta 4), pack-reused 85
Receiving objects: 100% (110/110), 148.40 KiB | 8.24 MiB/s, done.
Resolving deltas: 100% (23/23), done.
npm installの実行
git cloneコマンドを実行するとnextjs-frontendフォルダが作成されるのでnextjs-frontendフォルダに移動しJavaScriptのライブラリをインストールするためにnpm installコマンドを実行します。
% cd nextjs-frontend
% npm install
環境変数を設定する.env.exampleファイルがnextjs-frontendフォルダの下に作成されているのでコピーして.env.localファイルを作成します。中にはNEXT_PUBLIC_BACKEND_URLが設定されLaravelのURLが記述されています。
NEXT_PUBLIC_BACKEND_URL=http://localhost:8000
開発サーバの起動
npm run devコマンドを実行して開発サーバを起動します。php artisan serveではLaravelの開発サーバを起動しここではNext.jsの開発サーバを起動しています。
% npm run dev
> breeze-next@0.1.0 dev
> next dev
▲ Next.js 14.2.3
- Local: http://localhost:3000
- Environments: .env.local
✓ Starting...
✓ Ready in 5.7s
http://localhost:3000にブラウザからアクセスするとLaravelの初期画面(Laravel10の初期画面)が表示されます。これはバックエンドのLaravelの中にあるファイルによって表示されているのではなくNext.jsの中のファイルを利用して表示されています。Laravel11の初期画面はこの画面ではありません。
バックエンドで起動しているLaravelの開発サーバを停止しても上記のページは表示され続けます。
ここまでの作業でバックエンドのLaravelとフロントエンドのNext.jsの環境構築は完了です。
動作確認
breeze-nextのリポジトリではLaravelを利用する認証に必要な実装がすでに行われているため環境構築が完了したらそのままユーザの登録を行うことができます。
ユーザの登録
構築した環境を利用してユーザの登録を行います。動作確認を行う場合はフロントエンドのNext.jsとバックエンドのLaravelを起動しておく必要があります。
Laravelの見慣れたログイン画面ですがこれはNext.js側で作成されています。初期画面の右上のRegisterのリンクをクリックして登録したユーザ情報を入力します。
ユーザの登録が完了するとダッシュボード画面が表示されます。
Laravelのデータベースにユーザが登録されているか確認するためにtinkerを利用します。作成したユーザがusersテーブルに登録されていることを確認することができます。
% php artisan tinker
Psy Shell v0.12.4 (PHP 8.3.8 — cli) by Justin Hileman
> User::all();
[!] Aliasing 'User' to 'App\Models\User' for this Tinker session.
= Illuminate\Database\Eloquent\Collection {#5805
all: [
App\Models\User {#5396
id: 1,
name: "John Doe",
email: "john@example.com",
email_verified_at: null,
#password: "$2y$12$CXU/Y5Z9K7i2pRkoZhuqOuBBdkHb2IciDvyCQB16fpchYfAO0DQuy",
#remember_token: null,
created_at: "2024-08-06 15:13:52",
updated_at: "2024-08-06 15:13:52",
},
],
}
>
Next.jsで表示されているユーザ登録画面からLaravel側のテーブルにデータが挿入されることがわかりました。
初期画面の表示までの流れ
Next.jsはApp Routerとして設定が行われているのでlocalhost:3000にブラウザからアクセスするとappフディレクトリにあるpage.jsが実行されます。
import LoginLinks from '@/app/LoginLinks'
export const metadata = {
title: 'Laravel',
}
const Home = () => {
return (
<>
<div className="relative flex items-top justify-center min-h-screen bg-gray-100 dark:bg-gray-900 sm:items-center sm:pt-0">
<LoginLinks />
<div className="max-w-6xl mx-auto sm:px-6 lg:px-8">
//略
page.jsファイルの中でimportされているLoginLinksが初期画面表示の流れにとって重要なので中身を確認します。
'use client'
import Link from 'next/link'
import { useAuth } from '@/hooks/auth'
const LoginLinks = () => {
const { user } = useAuth({ middleware: 'guest' })
return (
<div className="hidden fixed top-0 right-0 px-6 py-4 sm:block">
{user ? (
<Link
href="/dashboard"
className="ml-4 text-sm text-gray-700 underline"
>
Dashboard
</Link>
) : (
<>
<Link
href="/login"
className="text-sm text-gray-700 underline"
>
Login
</Link>
<Link
href="/register"
className="ml-4 text-sm text-gray-700 underline"
>
Register
</Link>
</>
)}
</div>
)
}
export default LoginLinks
useAuth Hookを利用することでuser情報が戻されます。user情報が取得(ログインしている状態)ではDashboardの文字列が右上にリンクとともに表示されますがuser情報が取得できない場合はLog inとRegisterの文字列がリンクとともに表示されます。
ログインしていない場合はuser情報を使った分岐によって画面の右上上部にRegisterとLoginのリンクが表示されます。
ログインしている場合には右上にはDashboardへのリンクが表示されます。
ログインしている場合には右上にはDashboardへのリンクが表示されます。
Dashboard画面表示までの流れ
ログイン後にDashboard画面にリダイレクトされますがDashboard画面はsrc/app/(app)/dashboardのpage.jsファイルの内容が表示されます。
import Header from '@/app/(app)/Header'
export const metadata = {
title: 'Laravel - Dashboard',
}
const Dashboard = () => {
return (
<>
<Header title="Dashboard" />
<div className="py-12">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-gray-200">
You are logged in!
</div>
</div>
</div>
</div>
</>
)
}
export default Dashboard
上記を見る限り何もアクセスの制限を行っていないのでログインを行っていないくてもDashboard画面が表示されるように思われます。しかしログインしていない状態で/dashboardにアクセスすると/loginにリダイレクトされます。理由はNext.jsのapp Routerでは自動で(app)ディレクトリの直下にあるlayout.jsファイルが適用されます。(app)/layout.jsファイルを確認するとuseAuth Hookが実行されています。引数にはオブジェクトが設定されプロパティにmiddleware, 値にauthが設定されています。この値は後ほど利用します。
'use client'
import { useAuth } from '@/hooks/auth'
import Navigation from '@/app/(app)/Navigation'
import Loading from '@/app/(app)/Loading'
const AppLayout = ({ children }) => {
const { user } = useAuth({ middleware: 'auth' })
if (!user) {
return <Loading />
}
return (
<div className="min-h-screen bg-gray-100">
<Navigation user={user} />
<main>{children}</main>
</div>
)
}
export default AppLayout
useAuth Hookで認証の確認が行われていることが予想されるのでuseAuthのHookのコードを確認してみましょう。
useAuth Hook
useAuth Hookはhooks/auth.jsファイルの中に記述されています。
import useSWR from 'swr'
import axios from '@/lib/axios'
import { useEffect } from 'react'
import { useParams, useRouter } from 'next/navigation'
export const useAuth = ({ middleware, redirectIfAuthenticated } = {}) => {
const router = useRouter()
const params = useParams()
const {
data: user,
error,
mutate,
} = useSWR('/api/user', () =>
axios
.get('/api/user')
.then(res => res.data)
.catch(error => {
if (error.response.status !== 409) throw error
router.push('/verify-email')
}),
)
const csrf = () => axios.get('/sanctum/csrf-cookie')
//略
useEffect(() => {
if (middleware === 'guest' && redirectIfAuthenticated && user)
router.push(redirectIfAuthenticated)
if (
window.location.pathname === '/verify-email' &&
user?.email_verified_at
)
router.push(redirectIfAuthenticated)
if (middleware === 'auth' && error) logout()
}, [user, error])
return {
user,
register,
login,
forgotPassword,
resetPassword,
resendEmailVerification,
logout,
}
}
auth.jsファイルの中ではregisterやlogin関数も設定されていますがuseSWR Hookを利用してバックエンドの/api/userにアクセスを行いユーザ情報の取得を行っています。useSWRはデータ取得のための React HooksライブラリSWRのHookで第一引数にキーを設定して第2引数に関数を指定することができ第2引数の関数が実行されます。状態管理、データをキャッシュしたり関数を再実行することができる便利なHookです。
useAuthを実行すると/api/userへのアクセスを行っていますがエラーが戻された場合はエラーコード409以外はerrorがthrowされます。ログインによる認証が完了していない場合に/api/userにアクセスするとステータスコード401(“401 Unauthorized” error)が戻されます。useEffect Hookの中を見るとuserまたはerrorが更新すると処理が行われ、middlewareがauthでerrorの場合にはlogout関数が実行されます。つまりログインによる認証が行われていないとlogout関数が実行されることになります。
logout関数ではerrorが値を持っている時は/loginにリダイレクトされます。
const logout = async () => {
if (!error) {
await axios.post('/logout').then(() => mutate())
}
window.location.pathname = '/login'
}
ここまでの確認でログインしていない時に認証がかかったページ(例:/dashboard)にアクセスすると/loginにリダイレクトされることがわかりました。
新規ページの作成
useAuth Hookの動作が理解できたので新たにページを追加します。
(app)ディレクトリの下にusersディレクトリを作成してpage.jsファイルを作成します。dashboard/page.jsファイルを元に作成します。
import Header from '@/app/(app)/Header'
export const metadata = {
title: 'Laravel - User',
}
const User = () => {
return (
<>
<Header title="User" />
<div className="py-12">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-gray-200">
ユーザー情報
</div>
</div>
</div>
</div>
</>
)
}
export default User
ブラウザで確認すると
(auth)ディレクトリ下のlayout.jsが適用されるのでログインしていない状態で/usersにアクセスすると/loginにリダイレクトされます。
ヘッダーのリンクにUserを追加したい場合には、(app)ディレクトリ下のNavigation.jsファイルを更新します。
<div className="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<NavLink
href="/dashboard"
active={usePathname() === '/dashboard'}>
Dashboard
</NavLink>
<NavLink
href="/users"
active={usePathname() === '/users'}>
Users
</NavLink>
</div>
ブラウザで確認するとDashboardの横にUsersが表示され、リンクをクリックすることでページの移動を行うことができます。
ユーザ一覧の表示
ここまでの理解ができていればログインしたユーザのみ/usersにアクセスするとユーザ一覧を表示するページを簡単に作成することができます。
ユーザ一覧をLaravelのバックエンドから取得できるようにapi.phpファイルにルーティングを追加します。
Route::middleware(['auth:sanctum'])->get('/users', function () {
return \App\Models\User::all();
});
api/usersにアクセスを行い、ユーザ情報を取得、表示するUserList.jsファイルをcomponentsディレクトリの下に作成します。Clientコンポーネントとして作成します。
'use client'
import useSWR from 'swr'
import axios from '@/lib/axios'
const UserList = () => {
const { data: users, error } = useSWR('/api/users', () =>
axios
.get('/api/users')
.then(res => res.data)
.catch(error => {
console.error(error)
}),
)
if (error) return 'An error has occurred.'
return (
<ul>
{users?.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}
export default UserList
作成したUserList.jsファイルをusers/page.jsファイルでimportします。
import Header from '@/app/(app)/Header'
import UserList from '@/components/UserList'
export const metadata = {
title: 'Laravel - User',
}
const User = () => {
return (
<>
<Header title="User" />
<div className="py-12">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-gray-200">
<h1>ユーザー情報</h1>
<UserList />
</div>
</div>
</div>
</div>
</>
)
}
export default User
バックエンドのLaravelから取得したユーザ情報を表示することができました。
ここまでの動作確認で基本的な動作確認しか行っていませんがLaravelとNext.jsを一緒に利用できるということが確認できました。
Laravel9での動作確認
本文書を公開時にはLaravel9を利用していたのでその時の内容をそのまま残しています。現在はLaravel9を利用してもLaravel Breeze Next.js Editionが更新されているので下記の内容の通りではありません。
初期画面の表示までの流れ
Next.jsではlocalhost:3000にブラウザからアクセスするとpagesフォルダにあるindex.jsが実行されます。コードの量が多いので一部のみ記載しますがhookのuseAuthを利用してuser情報の取得を行っています。user情報が取得できた(ログインしている状態)か取得できなかったかによって表示される内容が変わります。
import Head from 'next/head'
import Link from 'next/link'
import { useAuth } from '@/hooks/auth'
export default function Home() {
const { user } = useAuth({ middleware: 'guest' })
return (
<>
<Head>
<title>Laravel</title>
</Head>
<div className="relative flex items-top justify-center min-h-screen bg-gray-100 dark:bg-gray-900 sm:items-center sm:pt-0">
<div className="hidden fixed top-0 right-0 px-6 py-4 sm:block">
{user ?
<Link href="/dashboard">
<a className="ml-4 text-sm text-gray-700 underline">
Dashboard
</a>
</Link>
:
<>
<Link href="/login">
<a className="text-sm text-gray-700 underline">Login</a>
</Link>
<Link href="/register">
<a className="ml-4 text-sm text-gray-700 underline">
Register
</a>
</Link>
</>
}
</div>
ログインしていない場合はuser情報を使った分岐によって画面の右上上部にRegisterとLoginのリンクが表示されます。
ログインしている場合には右上にはDashboardへのリンクが表示されます。
useAuth Hook
Githubのbreeze-nextリポジトリを利用して構築したNext.js全体を理解するためには認証機能の中心的な役割を果たすuseAuth Hookを理解する必要があります。
useAuth Hookが含まれているhooks/auth.jsファイルを確認するとregisterやlogin関数も設定されていますがuseSWR Hookを利用してバックエンドの/api/userにアクセスを行いユーザ情報の取得を行っています。useSWRはデータ取得のための React HooksライブラリSWRのHookで第一引数にキーを設定して第2引数に関数を指定することができ第2引数の関数が実行されます。状態管理、データをキャッシュしたり関数を再実行することができる便利なHookです。useSWRを利用しない場合はuseStateで状態を定義してuseEffectでデータを取得するといった処理が必要でありますが下記のコードを見てわかるようにuseSWRには状態管理などの機能が含まれています。
import useSWR from 'swr'
import axios from '@/lib/axios'
import { useEffect } from 'react'
import { useRouter } from 'next/router'
export const useAuth = ({ middleware, redirectIfAuthenticated } = {}) => {
const router = useRouter()
const { data: user, error, revalidate } = useSWR('/api/user', () =>
axios
.get('/api/user')
.then(res => res.data)
.catch(error => {
if (error.response.status !== 409) throw error
router.push('/verify-email')
}),
)
//略
useAuth Hookを利用することで取得するユーザ情報でログインしているかどうかチェックすることができます。新しく作成したページにユーザがログインしているかどうかによるアクセス制限を行いたい場合のuseAuth Hookの設定方法について確認します。
新規ページでuseAuth Hook
Next.jsではpagesフォルダにファイルを作成することで自動でルーティングが設定されるので新しいページを追加するためexample.jsファイルをpagesフォルダの下に作成します。
useAuthを利用し下記の設定を行うことでページにアクセスした時にユーザのログイン状態がチェックされます。ユーザがログインしている場合に/exampleにアクセスするとユーザ名とログアウトボタンが表示され、ログインしていない場合には/loginページにリダイレクトさせることができます。
import { useAuth } from '@/hooks/auth'
const Example = () => {
const { logout, user } = useAuth({ middleware: 'auth' })
return (
<>
<p>{user?.name}</p>
<button onClick={logout}>Sign out</button>
</>
)
}
export default Example
ログイン後に表示されるDashboardのページにもuseAuth Hookが利用されているので確認しておきましょう。Dashboardページの内容はpagesフォルダのdashboard.jsファイルに記述されています。
import AppLayout from '@/components/Layouts/AppLayout'
import Head from 'next/head'
const Dashboard = () => {
return (
<AppLayout
header={
<h2 className="font-semibold text-xl text-gray-800 leading-tight">
Dashboard
</h2>
}>
<Head>
<title>Laravel - Dashboard</title>
</Head>
<div className="py-12">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-gray-200">
You're logged in!
</div>
</div>
</div>
</div>
</AppLayout>
)
}
export default Dashboard
上記を見るとどこにもuseAuth Hookを見つけることができませんがレイアウトファイルであるAppLayout.jsファイルを確認するとuseAuth Hookの設定を確認することができます。
import Navigation from '@/components/Layouts/Navigation'
import { useAuth } from '@/hooks/auth'
const AppLayout = ({ header, children }) => {
const { user } = useAuth({ middleware: 'auth' })
//略
ユーザ一覧を表示
ここまでの理解ができていればログインしたユーザのみ/usersにアクセスするとユーザ一覧を表示するページを簡単に作成することができます。
ユーザ一覧をLaravelのバックエンドから取得できるようにapi.phpファイルにルーティングを追加します。
Route::middleware(['auth:sanctum'])->get('/users', function () {
return \App\Models\User::all();
});
フロントエンドのNext.js側ではdashboard.jsファイルを元にpagesフォルダにusers.jsファイルを作成します。データの取得はuseSWRを利用します。
import AppLayout from '@/components/Layouts/AppLayout'
import Head from 'next/head'
import useSWR from 'swr'
import axios from '@/lib/axios'
const Users = () => {
const { data: users, error } = useSWR('/api/users', () =>
axios
.get('/api/users')
.then(res => res.data)
.catch(error => {
console.error(error)
}),
)
if (error) return 'An error has occurred.'
return (
<AppLayout
header={
<h2> className="font-semibold text-xl text-gray-800 leading-tight">
Users
</h2>
}>
<Head>
<title>Laravel - Users</title>
</Head>
<div className="py-12">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div> className="p-6 bg-white border-b border-gray-200">
<ul>
{users?.map(user => (
<div> key={user.id}>{user.name}</div>
))}
</ul>
</div>
</div>
</div>
</div>
</AppLayout>
)
}
export default Users
ブラウザで確認するとユーザが1名しか追加されていないので下記のように表示されます。ログインしていない場合に/usersにアクセスするとログイン画面にリダイレクトされます。
別のブラウザを起動してユーザを追加し先ほど”John Doe”と表示されていたブラウザに再度フォーカスするとuseSWR Hookにより追加したユーザが表示されます。
Breeze apiとbreeze-nextリポジトリを利用することで認証機能が実装されたアプリケーションを構築できることが理解できました。