Web Application 実装ガイド
React Router v7(Framework モード)を利用した推奨アプリケーション実装パターンを紹介します。
TODO List を表示・状態を更新する機能を実装
TODO List 一覧を表示し、状態を更新する処理を実装していきます。Todo 更新後に保存ボタンを押す動作も含まれますが、本カタログでは実際にDBなどに保存するといった動作は行わず、そのような処理が行われる想定でローダーを表示するところまでの動きを実装します。
-
Welcome page
/
-
Todo list page
/todolist
前提条件
root.tsx, layout など基本的なパーツの実装方法は一部省略されています。ただし、本カタログの内容は React Router v7 プロジェクト新規生成時のものとほぼ変わりません。
大まかな処理の流れ
推奨構成として、以下の順番で実装していきます。プロジェクト全体の初期セットアップ後を想定しています。
対象ファイル | 実装内容のサマリー |
---|---|
src/types/todo.d.ts | Todo の型を定義 |
src/states/IsLoading.ts | データ処理中の状態を定義 |
src/hooks/useTodoSaver.tsx | Todoを保存する Custom Hook を定義 |
src/components/TodoListItem.tsx | TodoListの項目を再利用可能な構成として実装 |
src/pages/todolist/index.pages.tsx | TodoListページのUIを定義 |
src/routes/todolist.tsx | TodoList ページの起点とサーバー側処理(loader, action, 画面のエントリーポイント) |
src/routes.ts | TodoListページのルーティングを定義 |
他にも、必要に応じて適宜ディレクトリやファイルを構成してください。
src/types/todo.d.ts
Todo の型を定義
以下のように型定義をしておきます。各コンポーネントでの Props 定義や元データの型宣言で利用されます。
export type Todo = {
id: string
title: string
status: 'pending' | 'inProgress' | 'completed'
isStarred: boolean
// ...
}
また、src/types/index.ts
に以下のように定義しておくと、Import 分がシンプルになるため src/
以下全ディレクトリに作成しておくと良いです。
export * from './Todo.d'
src/states/IsLoading.ts
データ処理中の状態を定義
以下のように IsLoading の状態宣言をしておきます。本カタログでは Jotai というライブラリを利用します。
import { atom } from 'jotai'
export const IsLoadingAtom = atom<boolean>(false)
src/hooks/useTodoSaver.tsx
Todoを保存する Custom Hook を定義
Todo の変更内容を保存する処理を実装します。本カタログでは実際の更新処理は行わないですが、PUT /todolist
に更新された Todo を送信し、ログ出力する動作を実装します。
import { useAtom } from 'jotai'
import * as Atoms from '~/states'
export const useTodoSaver = () => {
const [isLoading, setIsLoading] = useAtom(Atoms.IsLoadingAtom)
const saveTodo = async (todo: Todo) => {
setIsLoading(true)
const saveResult = fetch('/todolist', {
method: 'PUT',
headers: { 'content-type': 'application/json', body: JSON.stringify(todo) },
})
.then((res) => res.json())
.finally(() => setIsLoading(false))
console.log('## saveResult - ', saveResult)
}
return { isLoading, saveTodo }
}
src/components/TodoListItem.tsx
TodoListの項目を再利用可能な構成として実装
Todo 一覧の項目を実装していきます。このような一覧の項目となるコンポーネントは、他の画面での再利用できるような形を想定して配置・作成します。
import type { Todo } from '~/types'
type Props = {
todo: Todo
}
export const TodoListItem: React.FC<Props> = ({ todo }) => {
// Some dynamic ui handler methods
return (
<div className="bg-white rounded-lg border border-gray-200 p-6 hover:shadow-md transition-shadow">
<div className="flex items-start justify-between">
<div className="flex-1 min-w-0">
<div className="flex items-center gap-3 mb-3">
<h3 className="text-lg font-medium text-gray-900 truncate">{todo.title}</h3>
{ /* 中略。カタログ AMI に全てのサンプルコードが含まれています。 */ }
</div>
</div>
</div>
</div>
)
}
src/pages/todolist/index.pages.tsx
TodoListページのUIを定義
Todo 一覧を表示させる TodoList ページの UI を実装していきます。
import { TodoListItem } from '~/components'
import type { Todo } from '~/types'
type Props = {
items: Todo[]
}
export const TodoListPage: React.FC<Props> = (props) => {
const { items } = props
return (
<>
<main className="max-w-6xl mx-auto px-4 py-8">
{ /* 中略。カタログ AMI に全てのサンプルコードが含まれています。*/ }
<div className="space-y-4">
{items.map((todo) => (
<TodoListItem key={todo.id} todo={todo} />
))}
</div>
</main>
</>
)
}
src/routes/todolist.tsx
TodoList の起点・サーバー側処理を実装
src/routes/
以下には、該当画面を読み込む際のサーバー側の処理(loader, action)と、meta タグなど各種設定が可能です。サーバー側からデータを取得し、前項の Page コンポーネントに Props 等の手段でデータを渡すことが可能で、loader を別ルートで実装し、非同期で GET /api/todolist
のような形で SPA と同じようなアプローチを取ることも可能です。
import type { MetaFunction } from 'react-router'
import type { Route } from './+types/todolist'
import type { Todo } from '~/types'
import { TODO_ITEMS } from '~/fixtures'
import { TodoListPage } from '~/pages'
export const meta: MetaFunction = () => {
// biome-ignore format: for better readability
return [
{ title: 'New React Router App - Todo List Page' },
{ name: 'description', content: 'Welcome to React Router!' }
]
}
export async function loader({/* params (path parameters) */}: Route.LoaderArgs) {
return { TODO_ITEMS }
}
const TodoListRoute = ({ loaderData }: { loaderData: { TODO_ITEMS: Todo[] } }) => {
const { TODO_ITEMS } = loaderData
return <TodoListPage items={TODO_ITEMS} />
}
export default TodoListRoute
詳細は、React Router v7 の公式ドキュメントをご確認ください。
src/routes.ts
TodoListページのルーティングを定義
最後に、画面を開いた時にどの routes ファイルにルーティングさせるかの設定を行います。ここでは、src/routes/todolist.tsx
に振り分けられるように設定しておきます。
import { layout, type RouteConfig, route } from '@react-router/dev/routes'
const PREFIX = './routes'
export default [
// biome-ignore format: for better readability
layout('./layouts/default.tsx', [
// Welcome page
route('/', `${PREFIX}/welcome.tsx`),
// Todo list page
route('/todolist', `${PREFIX}/todolist.tsx`),
]),
] satisfies RouteConfig
動作確認
ここまで進めてきたら、開発モードでアプリケーションを立ち上げて動作確認を行います。ローカル実行によるデバッグとテストに進んでください。