このプロジェクトは、React + TypeScript + Viteを使用して実装された企業検索システムです。
- 企業名のインクリメンタルサーチ
- 担当者情報の表示と検索
- 日本語 IME 入力対応
- レスポンシブデザイン
- CSRF 対策とレートリミット
- React 18
- TypeScript
- Vite
- Redux Toolkit
- Vitest
- MirageJS
# 依存関係のインストール
npm install
# 開発サーバーの起動
npm run dev
# テストの実行
npm test
# ビルド
npm run build
- 本番アプリケーションを開発する場合、型認識可能なlintルールを有効にすることを推奨します
export default tseslint.config({
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
},
})
-
企業情報と担当者情報の状態を分離して管理
-
企業情報の管理
companySlice
: 企業リストと検索状態を管理searchInput
: 検索入力値の管理filterText
: フィルタリング用テキストの管理status
: API リクエスト状態の管理
-
担当者情報の管理
peopleSlice
: 担当者リストと検索状態を管理filterText
: 担当者フィルタリング用テキストの管理peopleByCompany
: 会社ごとの担当者情報を管理
-
企業検索
- キャッシュなし
- 常に最新のデータを取得
- 理由:企業情報は頻繁に更新される可能性があるため
-
担当者情報
- 会社IDごとにキャッシュ
peopleByCompany
オブジェクトを使用- 理由:担当者情報は更新頻度が低いため
-
入力処理
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { if (e.key === "Enter" && !isComposing.current) { const trimmedInput = input.trim(); if (!trimmedInput) { console.log("検索条件が空のため検索を実行しません"); return; // 空文字では検索を実行しない } console.log("Enterキー押下で検索を実行"); dispatch(fetchCompanies(trimmedInput)); } };
-
検索処理
const handleCompositionEnd = ( e: React.CompositionEvent<HTMLInputElement> ) => { isComposing.current = false; // IME変換モード終了 console.log("IME変換モード終了"); console.log(e.data); // IME確定後に検索を実行 if (e.data?.trim()) { console.log("検索実行"); // e.data が undefined の場合を考慮 dispatch(fetchCompanies(input.trim())); } };
-
企業検索
- Enterキー押下またはIME確定時に検索実行
- 空文字列の場合は検索を実行しない
- 検索結果は最大300件まで表示
-
担当者検索
- 選択された企業の担当者をリアルタイムでフィルタリング
- 名前、部署、役職での検索が可能
- CSRF対策(トークンベース)
- レート制限(IPベース)
- 最大300件の検索結果制限
Vitestを使用した単体テストを実装
- Reduxスライスのテスト
- Reactコンポーネントのテスト
- 非同期処理のテスト
src/
├── components/ # Reactコンポーネント
├── store/ # Reduxストア
├── server/ # モックサーバー
└── test/ # テスト
- 検索結果は最大300件まで表示
- IME入力中は検索を実行しない
- CSRFトークンが無効な場合は403エラー
- レート制限超過時は429エラー