概要
東京エリアのホテルを条件検索できるWebアプリケーション。フロントエンドとバックエンドAPIを分離した構成で、検索・フィルタリング・ページネーションを実装した。
想定利用シーン
- 旅行予約サイトのホテル検索機能
- ECサイトの商品検索・フィルタリング
- 不動産ポータルの物件検索
- レストラン検索・口コミサイト
- 条件絞り込み付きの一覧系業務システム全般
この設計を応用できるシステム
- ECサイト(商品一覧・カテゴリ絞り込み・価格フィルタ)
- 求人検索(職種・勤務地・給与・条件フィルタ)
- 不動産検索(エリア・間取り・価格帯・駅距離)
- 店舗検索(ジャンル・エリア・評価・営業時間)
- 社内マスタ検索(社員・商品・取引先の一覧管理)
- 商品一覧画面(在庫管理・発注システムの検索UI)
Demo / GitHub
🔗 GitHub
スクリーンショット
トップページ — 検索バー + フィルタ + ホテルカード一覧(3カラムグリッド)
フィルタ使用中 — Ginzaエリアで絞り込み、4件の結果を表示
ホテル詳細ページ — 画像 + 評価 + 価格 + 住所 + 設備タグ
お気に入りページ — 登録済みホテル一覧(ハート切替で管理)
開発背景
検索・一覧・詳細表示・お気に入り管理は、旅行サイトだけでなくEC・不動産・求人など多くのWebサービスで共通する設計パターンである。そのため、API駆動型アーキテクチャを前提に実装し、再利用性の高い検索システムのデモとして開発した。
解決した課題
- 大量のデータから目的の情報を素早く見つけたい → エリア・価格帯・評価・キーワードの複合フィルタリング
- 気になった情報をあとで見返したい → お気に入り登録・一覧表示機能
- 一覧だけでは判断しにくい → 詳細ページで設備・住所・レビュー数まで確認可能
- 一度に全件表示すると見づらい → ページネーションで6件ずつ表示
主な機能
- ホテル一覧表示(カード形式、画像・価格・評価・エリア表示)
- 複合条件検索(エリア6区、価格帯、評価★3.0〜4.5+、キーワード)
- 検索結果件数表示(リアルタイムで該当件数を表示)
- ホテル詳細ページ(説明文、設備・サービスタグ、住所、レビュー数)
- お気に入り登録・解除(ハート切替、お気に入り一覧ページ)
- ページネーション(6件/ページ、ページ切替UI)
- フィルタリセット(ワンクリックで全条件クリア)
- レスポンシブ対応
使用技術
- フロントエンド: React 19 / TypeScript / React Router 7 / Vite 8
- バックエンド: Hono.js / Bun / TypeScript
- データ: JSON(25件のホテルデータ) / LocalStorage(お気に入り保存)
- デプロイ: Vercel
設計上の工夫
- API駆動型アーキテクチャ: フロントエンドとバックエンドを完全分離。検索・フィルタリング・ページネーションのロジックはすべてバックエンドAPIで処理し、フロントエンドはUIに集中する設計
- 責務の明確な分離: フロントエンドは表示に専念し、ビジネスロジックをAPI側へ集約することで責務を明確に分離
- カスタムHooksによる関心分離: useHotels / useHotelDetail / useFavorites の3つのHookで、データ取得・詳細表示・お気に入り管理をそれぞれ独立管理
システム構成
フロントエンド(React + Vite)
↓ fetch API
バックエンドAPI(Hono.js + Bun)
├── GET /api/hotels — フィルタリング + ページネーション
└── GET /api/hotels/:id — ホテル詳細
↓
ホテルデータ(hotels.json、25件)
お気に入り → LocalStorage(クライアント側で管理)
成果・実現したこと
- UIとビジネスロジックを分離した構成により、保守性・再利用性の高い検索システムを実現
- エリア・価格・評価・キーワードの複合フィルタリングをAPI側で処理し、フロントエンドの負荷を軽減
- カスタムHooksによる関心の分離で保守性の高いコード構成
- Bun + Hono.jsの軽量バックエンドにより、高速なAPI応答を実現
開発で直面した課題と解決方法
- 型定義の一貫性: フロントエンドとAPIで同じデータ構造を扱う必要があった → 共通のTypeScript型を利用し、APIレスポンスと画面表示の整合性を確保
- フィルタ変更時のページリセット: フィルタ条件を変更した際にページ番号がリセットされず、結果が表示されない問題 → フィルタ変更時にページ番号を自動的に1にリセットする共通ハンドラを実装
- お気に入りのデータ永続化: ブラウザ更新後もお気に入りデータを保持する必要があった → LocalStorageを活用し、useFavoritesカスタムHookで状態管理と永続化を一体化
このプロジェクトで学んだこと
- API駆動型アーキテクチャ: フロントとバックを分離した設計。マイクロサービスや大規模開発の基本パターンとして応用可能
- Hono.js + Bunの軽量バックエンド: Express.jsに代わる次世代フレームワークの実践。起動速度・レスポンス速度に優れた軽量構成
- 検索システム設計: フィルタリング・ページネーション・お気に入りなどを組み合わせることで、一覧系業務システムに共通する設計パターンを学んだ