React プロジェクトにおける各フォルダ(components、hooks、services、store、utils)の用途について詳しく説明します。これらのフォルダは、プロジェクトの構造を整理し、コードの可読性や保守性を向上させるために重要な役割を果たします。
1. components フォルダ
用途
components フォルダは、再利用可能な UI コンポーネントを格納するための場所です。これらのコンポーネントは、アプリケーションの様々な部分で使用され、UI の一貫性を保つ役割を担います。
内容
- プレゼンテーショナルコンポーネント: 状態を持たず、受け取ったプロパティに基づいて表示を行うコンポーネント。
- コンテナコンポーネント: 状態管理やロジックを担当し、プレゼンテーショナルコンポーネントにデータを渡すコンポーネント。
例
src/
├── components/
│   ├── Button/
│   │   ├── Button.jsx
│   │   ├── Button.test.js
│   │   └── Button.module.css
│   └── Header/
│       ├── Header.jsx
│       ├── Header.test.js
│       └── Header.module.cssButton.jsx
import React from 'react';
import styles from './Button.module.css';
const Button = ({ onClick, children }) => {
  return (
    <button className={styles.button} onClick={onClick}>
      {children}
    </button>
  );
};
export default Button;2. hooks フォルダ
用途
hooks フォルダには、カスタム React フックを格納します。カスタムフックは、再利用可能なロジックを抽象化し、複数のコンポーネント間で共有するために使用されます。
内容
- カスタムフック: 特定の機能やロジックを実装したフック(例: データフェッチング、フォーム処理、認証など)。
例
src/
├── hooks/
│   └── useAuth.jsuseAuth.js
import { useState, useEffect } from 'react';
import { authService } from '../services/authService';
const useAuth = () => {
  const [user, setUser] = useState(null);
  useEffect(() => {
    authService.getCurrentUser().then(setUser);
  }, []);
  const login = async (credentials) => {
    const loggedInUser = await authService.login(credentials);
    setUser(loggedInUser);
  };
  const logout = () => {
    authService.logout();
    setUser(null);
  };
  return { user, login, logout };
};
export default useAuth;3. services フォルダ
用途
services フォルダには、API 呼び出しや外部サービスとの通信を担当するロジックを格納します。これにより、ビジネスロジックと UI ロジックを分離し、コードの再利用性とテストのしやすさを向上させます。
内容
- API クライアント: REST API や GraphQL エンドポイントとの通信を行う関数やクラス。
- 認証サービス: ログイン、ログアウト、ユーザー情報の取得などの認証関連のロジック。
例
src/
├── services/
│   └── api.jsapi.js
import axios from 'axios';
const apiClient = axios.create({
  baseURL: 'https://api.example.com',
  headers: {
    'Content-Type': 'application/json',
  },
});
export const getPosts = () => apiClient.get('/posts');
export const getPostById = (id) => apiClient.get(`/posts/${id}`);
export const createPost = (postData) => apiClient.post('/posts', postData);
// 他のAPI呼び出しもここに追加4. store フォルダ
用途
store フォルダは、アプリケーションのグローバルな状態管理を担当します。Redux や Context API などの状態管理ライブラリを使用する場合、このフォルダに関連するファイルを配置します。
内容
- アクション(actions): 状態を変更するためのイベントやデータ。
- リデューサー(reducers): アクションに応じて状態を更新する関数。
- ストア(store): アプリケーション全体の状態を保持する場所。
例
src/
├── store/
│   ├── actions/
│   │   └── authActions.js
│   ├── reducers/
│   │   └── authReducer.js
│   └── store.jsstore.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import authReducer from './reducers/authReducer';
const rootReducer = combineReducers({
  auth: authReducer,
  // 他のリデューサーをここに追加
});
const store = createStore(rootReducer, applyMiddleware(thunk));
export default store;
authActions.js
import { LOGIN_SUCCESS, LOGOUT } from '../types';
import { authService } from '../../services/authService';
export const login = (credentials) => async (dispatch) => {
  const user = await authService.login(credentials);
  dispatch({ type: LOGIN_SUCCESS, payload: user });
};
export const logout = () => (dispatch) => {
  authService.logout();
  dispatch({ type: LOGOUT });
};authReducer.js
import { LOGIN_SUCCESS, LOGOUT } from '../types';
const initialState = {
  user: null,
};
const authReducer = (state = initialState, action) => {
  switch (action.type) {
    case LOGIN_SUCCESS:
      return { ...state, user: action.payload };
    case LOGOUT:
      return { ...state, user: null };
    default:
      return state;
  }
};
export default authReducer;5. utils フォルダ
用途
utils フォルダには、アプリケーション全体で再利用可能なユーティリティ関数やヘルパー関数を格納します。これらの関数は、特定のビジネスロジックに依存せず、汎用的に使用できるものです。
内容
- フォーマット関数: 日付や数値のフォーマット。
- バリデーション関数: 入力値の検証。
- その他のヘルパー関数: データ変換、計算処理など。
例
src/
├── utils/
│   └── formatDate.jsformatDate.js
export const formatDate = (date, locale = 'en-US') => {
  return new Date(date).toLocaleDateString(locale, {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  });
};
// 他のユーティリティ関数もここに追加まとめ
各フォルダの役割を明確に分けることで、React プロジェクトの構造が整理され、以下のようなメリットが得られます。
- 可読性の向上: 新しい開発者がプロジェクトに参加しやすくなります。
- 保守性の向上: バグ修正や機能追加が容易になります。
- 再利用性の向上: コンポーネントや関数を他の部分でも簡単に再利用できます。
- スケーラビリティ: プロジェクトが大規模になっても対応しやすくなります。
これらのフォルダ構成を適切に採用することで、効率的かつ効果的な開発が可能となります。プロジェクトのニーズに合わせて柔軟に構造を調整し、最適な開発環境を整えてください。


