0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🎯 React × Context API で作るスケーラブルな状態管理とクリーンアーキテクチャ(MVC風構成)

Posted at

Reactで中〜大規模アプリを構築する際、「状態管理の整理」「フォルダ構成の一貫性」「保守性」が重要になります。

本記事では、Context API × MVC風構成を活用して、以下を実現するアーキテクチャの実装手順をご紹介します。

  • グローバルな状態管理
  • データ取得(API)の責務分離
  • フォルダ構成の明確化(可読性・再利用性UP)

✅ 想定されるフォルダ構成

以下のような構成をベースに実装します。

src/
├── api/                # API呼び出し(Controller的役割)
│   └── countryApi.js
├── components/         # 再利用可能なUIコンポーネント
│   └── Header/
│       └── CountryDropdown.jsx
├── context/            # グローバル状態(Context API)
│   ├── CountryContext.jsx
│   └── CountryProvider.jsx
├── hooks/              # カスタムフック
│   └── useCountries.js
├── pages/              # ルーティングページ(View)
│   └── Home.jsx
├── services/           # ビジネスロジック(Model)
│   └── countryService.js
├── App.jsx             # アプリのエントリポイント
├── index.js            # ReactDOMのマウント
└── styles/             # 共通スタイル

🌐 1. Country API を分離(api/countryApi.js

// src/api/countryApi.js
import axios from "axios";

export const fetchCountries = async () => {
  const res = await axios.get("https://countriesnow.space/api/v0.1/countries/");
  return res.data.data.map((country) => country.country); // 国名だけ抽出
};

🧠 2. グローバル状態用のContextを作成(context/CountryContext.jsx

// src/context/CountryContext.jsx
import { createContext } from "react";

export const CountryContext = createContext();

🧩 3. プロバイダーコンポーネント(context/CountryProvider.jsx

// src/context/CountryProvider.jsx
import { useEffect, useState } from "react";
import { CountryContext } from "./CountryContext";
import { fetchCountries } from "../api/countryApi";

export const CountryProvider = ({ children }) => {
  const [countryList, setCountryList] = useState([]);

  useEffect(() => {
    const load = async () => {
      const countries = await fetchCountries();
      setCountryList(countries);
    };
    load();
  }, []);

  return (
    <CountryContext.Provider value={{ countryList }}>
      {children}
    </CountryContext.Provider>
  );
};

🧱 4. コンポーネントでContextを使用(components/Header/CountryDropdown.jsx

import React, { useContext, useState } from "react";
import Dialog from "@mui/material/Dialog";
import Button from "@mui/material/Button";
import { IoCloseOutline } from "react-icons/io5";
import { CountryContext } from "../../context/CountryContext";

const CountryDropdown = () => {
  const [isOpen, setIsOpen] = useState(false);
  const { countryList } = useContext(CountryContext);

  return (
    <>
      <Button onClick={() => setIsOpen(true)}>現在の国を選択</Button>

      <Dialog open={isOpen} onClose={() => setIsOpen(false)}>
        <div className="dialog-content">
          <Button
            className="close-button"
            variant="text"
            onClick={() => setIsOpen(false)}
          >
            <IoCloseOutline />
          </Button>

          <ul>
            {countryList.map((country, index) => (
              <li key={index}>
                <Button onClick={() => setIsOpen(false)}>{country}</Button>
              </li>
            ))}
          </ul>
        </div>
      </Dialog>
    </>
  );
};

export default CountryDropdown;

🚀 5. AppコンポーネントでProviderをラップ(App.jsx

import "./App.css";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { CountryProvider } from "./context/CountryProvider";
import Home from "./pages/Home";
import Header from "./components/Header";

function App() {
  return (
    <CountryProvider>
      <BrowserRouter>
        <Header />
        <Routes>
          <Route path="/" element={<Home />} />
        </Routes>
      </BrowserRouter>
    </CountryProvider>
  );
}

export default App;

🧠 補足:なぜ分離が重要?

役割
API層 (/api/) 外部通信だけを担う(axiosなど)
Service層 (/services/) ビジネスロジックの管理
Context (/context/) グローバルステート管理
Component UIの表示と最小限のロジック
Hooks ロジックの再利用・分離

📌 まとめ

Context API を用いた状態管理において、責務を分離したフォルダ構成をとることで、以下が実現できます。

  • 保守性の高いコード
  • コンポーネントの再利用性向上
  • チーム開発でも迷いづらい明瞭な責務分担

✍️ 最後に

これからReactアプリを中長期で運用していく予定がある方には、このような構成を初期から取り入れることを強くおすすめします


お気に召しましたら、ぜひいいね・フォローお願いします 🙌
質問などありましたらお気軽にコメントください!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?