Reactプロジェクトの始め方|create-react-appは古い?

2025年版React開発環境の構築ガイド。create-react-appの現状から最新のVite、Next.js、Remixまで、目的別の最適なセットアップ方法を解説します。

Learning Next 運営
58 分で読めます

みなさん、こんなことありませんか?

「create-react-appって、まだ使っていいの?」 「最近よく聞くViteって何?どっちがいいの?」 「Next.jsとかRemix、選択肢多すぎて迷う…」

そんな悩みを抱えていませんか?

React開発環境は2023年以降、大きく変わりました。 長年愛用されてきたcreate-react-app(CRA)が停滞中。 代わりに、もっと速くて現代的な選択肢が人気です。

でも、どれを選べばいいのか分からない。 そんな方も多いはずです。

この記事では、2025年版のReact始め方を解説します。 create-react-appの問題から最新ツールまで。 実際のセットアップ手順も含めて、詳しく説明しますね。

一緒に、現代的なReact環境を作っていきましょう!

create-react-appの現状

まず、従来のcreate-react-appの状況を見てみましょう。 何が問題なのか、理解することが大切です。

create-react-appって何だった?

create-react-app(CRA)は、Reactチームが作った公式ツールでした。 複雑な設定なしで、すぐにReactが始められる画期的なツール。

# 従来は設定が大変でした
npm install react react-dom
npm install --save-dev webpack webpack-cli webpack-dev-server
npm install --save-dev @babel/core @babel/preset-react
npm install --save-dev css-loader style-loader
# さらに多くの設定が必要…

# CRAなら一発で完了
npx create-react-app my-app
cd my-app
npm start

とってもシンプルで便利でしたよね。 でも、時代は変わりました。

CRAの良いところ(過去の話)

// CRAで作成されたプロジェクト構造
my-app/
├── public/
│   ├── index.html
│   └── favicon.ico
├── src/
│   ├── App.js
│   ├── App.css
│   ├── index.js
│   └── index.css
├── package.json
└── README.md

// すぐに使える開発環境
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <h1>Hello React!</h1>
      </header>
    </div>
  );
}

export default App;

Hot reload、ES6+、CSS imports、画像処理。 これらが標準で使えました。 初心者にはとても親切でしたね。

何が問題になったの?

1. 遅い、とにかく遅い

# CRAの起動時間
$ npm start
Starting the development server...

Files successfully emitted, waiting for typecheck results...
Issues checking in progress...
No issues found.

webpack compiled with 1 warning

Local:            http://localhost:3000

# 初回起動: 15-30秒
# ホットリロード: 2-5秒
# ビルド時間: 30秒-2分

現代の基準では、かなり遅いです。 開発効率が悪くなってしまいました。

2. 古いツールに依存

// CRAのpackage.json(2023年版)
{
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1"  // 長期間更新されてない
  },
  "devDependencies": {
    // webpack 4系(最新はwebpack 5)
    // Babel設定が古い
    // Node.js最新バージョンへの対応遅れ
  }
}

技術の進歩に追いついていません。 最新機能が使えないのは困りますよね。

3. カスタマイズが困難

# 設定をカスタマイズするには "eject" が必要
npm run eject

# Warning: この操作は取り消せません
# 設定ファイルが大量に展開される
# 保守が困難になる

ejectすると、もう戻れません。 設定ファイルの山に埋もれることに…

4. 開発チームの問題

  • 最後のメジャーアップデート: 2022年
  • 未解決のIssue: 1000件以上
  • Pull Request: 300件以上が未対応
  • 開発者コミュニティからの懸念の声

もはや、積極的に開発されていません。 これは致命的ですよね。

現代のツールとの比較

// 開発体験の違い
const comparison = {
  CRA: {
    startupTime: '15-30秒',
    hotReload: '2-5秒',
    bundleSize: '大きい(最適化不十分)',
    typeScript: '追加設定が必要',
    testing: 'Jest(古いバージョン)'
  },
  
  modernTools: {
    startupTime: '1-3秒',
    hotReload: '即座(100ms以下)',
    bundleSize: '小さい(最新最適化)',
    typeScript: '標準装備',
    testing: '最新テストツール'
  }
};

差は歴然ですね。 もう、CRAを選ぶ理由がありません。

CRAから移行すべき場面

  • 新規プロジェクト: 必須で移行を検討
  • 開発速度に不満: 強く推奨
  • TypeScript導入したい: 推奨
  • 既存の大規模プロジェクト: 慎重に検討
  • 学習目的・小規模: 任意(CRAでも学習には十分)

あなたのプロジェクトはどれに当てはまりますか?

現代的な選択肢を比較してみよう

2025年現在、素晴らしい選択肢がたくさんあります。 それぞれの特徴を詳しく見ていきましょう。

1. Vite - 高速開発の最新ツール

# Viteでプロジェクト作成
npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install
npm run dev

# 起動時間: 1-2秒
# ホットリロード: 即座

Viteの特徴

// vite.config.js - シンプルで強力
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000,
    open: true
  },
  build: {
    sourcemap: true,
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          lodash: ['lodash']
        }
      }
    }
  }
})

Viteの魅力

  • 起動が爆速: ESモジュール活用でほぼ即座
  • HMRが超高速: 100ms以下で差分更新
  • バンドルサイズ小: Tree-shaking + Rollup最適化
  • 設定がシンプル: 分かりやすい設定ファイル
  • TypeScript標準: 追加設定なしで使える
  • CSS対応: Sass、Less、Stylus対応
// TypeScriptサポート例
interface User {
  id: number;
  name: string;
  email: string;
}

const UserComponent: React.FC<{ user: User }> = ({ user }) => {
  return (
    <div className="user-card">
      <h3>{user.name}</h3>
      <p>{user.email}</p>
    </div>
  );
};

Viteが適している場面

  • SPAアプリケーション
  • 高速な開発体験が必要
  • バンドルサイズを最小化したい
  • モダンブラウザをターゲット
  • カスタマイズ性を重視
  • ライブラリ開発
  • プロトタイプ作成

学習や個人開発には、最高の選択肢です。

2. Next.js - Reactフルスタックフレームワーク

# Next.jsプロジェクト作成
npx create-next-app@latest my-nextjs-app
cd my-nextjs-app
npm run dev

# App Router + TypeScript + TailwindCSS + ESLint

Next.jsの特徴

// app/page.tsx - App Router(Next.js 13+)
export default function HomePage() {
  return (
    <main className="container mx-auto p-4">
      <h1 className="text-3xl font-bold">Welcome to Next.js</h1>
      <p>Server-side rendering ready!</p>
    </main>
  );
}

// app/users/[id]/page.tsx - 動的ルーティング
interface Props {
  params: { id: string };
}

export default async function UserPage({ params }: Props) {
  const user = await fetchUser(params.id); // サーバーサイドで実行
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

// データフェッチもサーバーサイド
async function fetchUser(id: string) {
  const response = await fetch(`${process.env.API_URL}/users/${id}`);
  return response.json();
}

Next.jsの先進機能

// next.config.js - 豊富な設定オプション
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    appDir: true, // App Router
    serverComponents: true // React Server Components
  },
  images: {
    domains: ['example.com'] // 画像最適化
  },
  async redirects() {
    return [
      {
        source: '/old-page',
        destination: '/new-page',
        permanent: true,
      },
    ];
  }
};

module.exports = nextConfig;

Next.jsが適している場面

  • SEOが重要なWebサイト
  • サーバーサイドレンダリングが必要
  • 静的サイト生成(SSG)
  • API routesでバックエンドも構築
  • 本格的なWebアプリケーション
  • eコマースサイト
  • ブログやCMS
  • パフォーマンスを重視

企業サイトや本格的なWebアプリには最適です。

3. Remix - データ中心のフルスタック

# Remixプロジェクト作成
npx create-remix@latest my-remix-app
cd my-remix-app
npm run dev

Remixの特徴

// app/routes/users.$userId.tsx
import { json, LoaderFunctionArgs } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";

// サーバーサイドローダー
export async function loader({ params }: LoaderFunctionArgs) {
  const user = await fetchUser(params.userId);
  return json({ user });
}

// アクション(フォーム処理)
export async function action({ request }: ActionFunctionArgs) {
  const formData = await request.formData();
  const name = formData.get("name");
  
  await updateUser({ name });
  return redirect("/users");
}

// コンポーネント
export default function UserProfile() {
  const { user } = useLoaderData<typeof loader>();
  
  return (
    <div>
      <h1>{user.name}</h1>
      
      <Form method="post">
        <input name="name" defaultValue={user.name} />
        <button type="submit">更新</button>
      </Form>
    </div>
  );
}

Remixの革新的な機能

// Progressive Enhancement
// JavaScriptが無効でも動作するフォーム
export default function ContactForm() {
  return (
    <Form method="post" action="/contact">
      <input name="email" type="email" required />
      <textarea name="message" required />
      <button type="submit">送信</button>
    </Form>
  );
}

// Error Boundary(ルートレベル)
export function ErrorBoundary() {
  return (
    <div className="error-container">
      <h1>おっと、何かが間違っていました</h1>
      <p>申し訳ございませんが、エラーが発生しました。</p>
    </div>
  );
}

Remixが適している場面:

  • データ重視アプリ
  • フォーム処理が多い
  • Web標準準拠を重視
  • Progressive Enhancement
  • 管理システム
  • CRM、在庫管理

4. T3 Stack - タイプセーフなフルスタック

# T3 Stackプロジェクト作成
npm create t3-app@latest my-t3-app
cd my-t3-app
npm run dev

T3 Stackの構成

// T3 Stackのテクノロジー
const t3Stack = {
  frontend: 'Next.js (TypeScript)',
  styling: 'TailwindCSS',
  database: 'Prisma + PlanetScale/SQLite',
  authentication: 'NextAuth.js',
  api: 'tRPC(type-safe API)',
  deployment: 'Vercel'
};

// tRPCによるタイプセーフAPI
export const postRouter = createTRPCRouter({
  getAll: publicProcedure.query(({ ctx }) => {
    return ctx.db.post.findMany();
  }),
  
  create: protectedProcedure
    .input(z.object({
      title: z.string().min(1),
      content: z.string().min(1),
    }))
    .mutation(async ({ ctx, input }) => {
      return ctx.db.post.create({
        data: {
          title: input.title,
          content: input.content,
          authorId: ctx.session.user.id,
        },
      });
    }),
});

// フロントエンドでのタイプセーフな使用
function PostList() {
  const { data: posts, isLoading } = api.post.getAll.useQuery();
  const createPost = api.post.create.useMutation();
  
  if (isLoading) return <div>Loading...</div>;
  
  return (
    <div>
      {posts?.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.content}</p>
        </article>
      ))}
    </div>
  );
}

T3 Stackが適している場面:

  • エンタープライズレベル
  • フルタイプセーフティが必要
  • チーム開発
  • 本格的な企業システム

選択肢比較表

const comparisonTable = {
  Vite: {
    setup: '★★★★★',
    performance: '★★★★★',
    features: '★★★☆☆',
    learningCurve: '★★☆☆☆',
    bestFor: 'SPA、ライブラリ開発'
  },
  
  NextJS: {
    setup: '★★★★☆',
    performance: '★★★★☆',
    features: '★★★★★',
    learningCurve: '★★★☆☆',
    bestFor: 'SEO重視、フルスタック'
  },
  
  Remix: {
    setup: '★★★☆☆',
    performance: '★★★★☆',
    features: '★★★★☆',
    learningCurve: '★★★★☆',
    bestFor: 'データ重視、Web標準'
  },
  
  T3Stack: {
    setup: '★★★☆☆',
    performance: '★★★★☆',
    features: '★★★★★',
    learningCurve: '★★★★★',
    bestFor: 'タイプセーフ、本格開発'
  }
};

どれもそれぞれ素晴らしい特徴がありますね。 次は、目的別の選び方を見ていきましょう。

目的別のおすすめツール

プロジェクトの目的に応じて、最適なツールを選んでみましょう。 具体的な使い分け方を解説します。

学習・プロトタイプ作成

おすすめ: Vite

// 学習目的やプロトタイプには Vite が最適
const learningProject = {
  tool: 'Vite',
  reason: [
    'セットアップが最速',
    '設定がシンプル',
    'React本来の機能に集中できる',
    'ホットリロードが高速'
  ]
};
# セットアップ例
npm create vite@latest my-learning-app -- --template react-ts
cd my-learning-app
npm install
npm run dev

学習に最適なプロジェクト構造:

my-learning-app/
├── src/
│   ├── components/
│   │   ├── Counter.tsx      // useState学習
│   │   ├── TodoList.tsx     // state管理学習
│   │   └── UserProfile.tsx  // props学習
│   ├── hooks/
│   │   ├── useCounter.ts    // カスタムフック学習
│   │   └── useLocalStorage.ts
│   ├── App.tsx
│   └── main.tsx
└── package.json
// 学習用コンポーネント例
function LearningApp() {
  return (
    <div className="learning-app">
      <h1>React学習アプリ</h1>
      <Counter />
      <TodoList />
      <UserProfile user={mockUser} />
    </div>
  );
}

学習にはViteが一番です。 余計な設定に悩まず、Reactに集中できます。

個人プロジェクト・SPA

おすすめ: Vite + React Router

// 個人開発やSPAには Vite + React Router
const spaProject = {
  tool: 'Vite + React Router',
  additionalLibraries: [
    'React Router Dom',
    'React Query/TanStack Query',
    'Zustand/Context API',
    'TailwindCSS'
  ]
};

プロジェクト例: タスク管理アプリ

my-spa-app/
├── src/
│   ├── pages/
│   │   ├── Dashboard.tsx
│   │   ├── Projects.tsx
│   │   └── Settings.tsx
│   ├── components/
│   │   ├── TaskCard.tsx
│   │   ├── ProjectList.tsx
│   │   └── Navigation.tsx
│   ├── hooks/
│   │   ├── useTasks.ts
│   │   └── useProjects.ts
│   ├── store/
│   │   └── taskStore.ts
│   └── api/
│       └── client.ts
// SPA用のルーティング設定
import { createBrowserRouter, RouterProvider } from 'react-router-dom';

const router = createBrowserRouter([
  {
    path: '/',
    element: <Layout />,
    children: [
      { index: true, element: <Dashboard /> },
      { path: 'projects', element: <Projects /> },
      { path: 'projects/:id', element: <ProjectDetail /> },
      { path: 'settings', element: <Settings /> }
    ]
  }
]);

function App() {
  return <RouterProvider router={router} />;
}

個人プロジェクトには、自由度の高いViteがピッタリです。

ビジネスサイト・ブログ

おすすめ: Next.js

// SEOが重要なサイトには Next.js
const businessWebsite = {
  tool: 'Next.js',
  features: [
    'SSG(静的サイト生成)',
    'Image最適化',
    'SEO対応',
    'サイトマップ自動生成'
  ]
};

ビジネスサイト構造例:

my-business-site/
├── app/
│   ├── (marketing)/
│   │   ├── page.tsx          // ホームページ
│   │   ├── about/page.tsx    // 会社概要
│   │   ├── services/page.tsx // サービス
│   │   └── contact/page.tsx  // お問い合わせ
│   ├── blog/
│   │   ├── page.tsx          // ブログ一覧
│   │   └── [slug]/page.tsx   // 記事詳細
│   ├── components/
│   │   ├── Header.tsx
│   │   ├── Footer.tsx
│   │   └── ContactForm.tsx
│   └── layout.tsx
// SEO最適化例
export const metadata: Metadata = {
  title: '株式会社サンプル | Webソリューション',
  description: 'モダンなWeb開発でビジネスの成長をサポートします',
  keywords: 'Web開発, React, Next.js, SEO',
  openGraph: {
    title: '株式会社サンプル',
    description: 'モダンなWeb開発でビジネスの成長をサポート',
    images: ['/og-image.jpg']
  }
};

SEOが重要なサイトには、Next.jsが最強です。

Eコマース・複雑なWebアプリ

おすすめ: Next.js + 追加ツール

// 複雑なアプリケーションには Next.js + 追加ツール
const ecommerceApp = {
  tool: 'Next.js',
  additionalTools: [
    'Prisma(DB ORM)',
    'NextAuth.js(認証)',
    'Stripe(決済)',
    'Vercel(ホスティング)'
  ]
};

Eコマース構造例:

my-ecommerce/
├── app/
│   ├── (shop)/
│   │   ├── page.tsx              // 商品一覧
│   │   ├── products/[id]/page.tsx // 商品詳細
│   │   ├── cart/page.tsx         // カート
│   │   └── checkout/page.tsx     // 決済
│   ├── (auth)/
│   │   ├── login/page.tsx
│   │   └── register/page.tsx
│   ├── (admin)/
│   │   ├── dashboard/page.tsx
│   │   └── products/page.tsx
│   ├── api/
│   │   ├── products/route.ts
│   │   ├── orders/route.ts
│   │   └── stripe/route.ts
│   └── components/
│       ├── ProductCard.tsx
│       ├── CartItem.tsx
│       └── CheckoutForm.tsx
// API Routes例(決済処理)
import { NextRequest, NextResponse } from 'next/server';
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function POST(request: NextRequest) {
  try {
    const { amount, currency = 'jpy' } = await request.json();
    
    const paymentIntent = await stripe.paymentIntents.create({
      amount,
      currency,
      metadata: {
        order_id: generateOrderId()
      }
    });
    
    return NextResponse.json({
      client_secret: paymentIntent.client_secret
    });
  } catch (error) {
    return NextResponse.json(
      { error: 'Payment intent creation failed' },
      { status: 500 }
    );
  }
}

本格的なWebアプリには、Next.jsの豊富な機能が活躍します。

データ重視のアプリケーション

おすすめ: Remix

// データ操作が多いアプリには Remix
const dataIntensiveApp = {
  tool: 'Remix',
  strengths: [
    'フォーム処理に特化',
    'サーバーサイドバリデーション',
    'Progressive Enhancement',
    'ネストされたルーティング'
  ],
  
  example: '顧客管理システム、在庫管理、CRM'
};
// Remixでのデータ処理例
export async function loader({ params }: LoaderFunctionArgs) {
  const customer = await getCustomer(params.customerId);
  if (!customer) throw new Response("Not Found", { status: 404 });
  return json({ customer });
}

export async function action({ request, params }: ActionFunctionArgs) {
  const formData = await request.formData();
  const updates = Object.fromEntries(formData);
  
  // サーバーサイドバリデーション
  const errors = validateCustomerData(updates);
  if (errors) {
    return json({ errors }, { status: 400 });
  }
  
  await updateCustomer(params.customerId, updates);
  return redirect(`/customers/${params.customerId}`);
}

export default function EditCustomer() {
  const { customer } = useLoaderData<typeof loader>();
  const actionData = useActionData<typeof action>();
  
  return (
    <Form method="post">
      <input
        name="name"
        defaultValue={customer.name}
        aria-invalid={actionData?.errors?.name ? true : undefined}
      />
      {actionData?.errors?.name && (
        <span className="error">{actionData.errors.name}</span>
      )}
      
      <button type="submit">更新</button>
    </Form>
  );
}

フォーム処理やデータ管理が多いなら、Remixが最適です。

本格的な企業アプリケーション

おすすめ: T3 Stack

// エンタープライズレベルには T3 Stack
const enterpriseApp = {
  tool: 'T3 Stack',
  benefits: [
    'フルタイプセーフティ',
    'スケーラブルな構造',
    'モダンなツールチェーン',
    'チーム開発に最適'
  ],
  
  examples: [
    '社内ダッシュボード',
    'プロジェクト管理システム',
    '顧客管理システム',
    'レポーティングツール'
  ]
};

企業レベルのアプリには、型安全性とスケーラビリティが重要です。

選択フローチャート

// プロジェクト選択のフローチャート
function selectTool(requirements) {
  if (requirements.purpose === 'learning') {
    return 'Vite';
  }
  
  if (requirements.seo === false && requirements.type === 'spa') {
    return 'Vite + React Router';
  }
  
  if (requirements.seo === true) {
    if (requirements.complexity === 'simple') {
      return 'Next.js';
    }
    if (requirements.dataProcessing === 'heavy') {
      return 'Remix';
    }
  }
  
  if (requirements.teamSize > 5 && requirements.typeScript === true) {
    return 'T3 Stack';
  }
  
  // デフォルト推奨
  return 'Next.js';
}

// 使用例
const projectRequirements = {
  purpose: 'business',
  seo: true,
  complexity: 'medium',
  dataProcessing: 'light',
  teamSize: 3,
  typeScript: true
};

const recommendedTool = selectTool(projectRequirements);
console.log(`推奨ツール: ${recommendedTool}`);

あなたのプロジェクトにはどれが合いそうですか?

実践:Viteでプロジェクト作成

最も汎用性が高いViteを使って、実際にプロジェクトを作ってみましょう。 手順を詳しく解説します。

基本セットアップ

# 1. プロジェクト作成
npm create vite@latest my-react-app -- --template react-ts
cd my-react-app

# 2. 依存関係のインストール
npm install

# 3. 開発サーバー起動
npm run dev

# 出力例:
# VITE v5.0.0  ready in 200 ms
# ➜  Local:   http://localhost:5173/
# ➜  Network: use --host to expose

たった3ステップで完了! この速さがViteの魅力ですね。

生成されるプロジェクト構造

my-react-app/
├── public/
│   └── vite.svg
├── src/
│   ├── assets/
│   │   └── react.svg
│   ├── App.css
│   ├── App.tsx
│   ├── index.css
│   ├── main.tsx
│   └── vite-env.d.ts
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts

シンプルで分かりやすい構造です。

初期ファイルの理解

// main.tsx - アプリケーションのエントリーポイント
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)
// App.tsx - メインコンポーネント
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

function App() {
  const [count, setCount] = useState(0)

  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
    </>
  )
}

export default App

すでに動くアプリができています。 TypeScriptも標準で使えますね。

必要なライブラリの追加

# ルーティング
npm install react-router-dom
npm install -D @types/react-router-dom

# 状態管理
npm install zustand

# データフェッチ
npm install @tanstack/react-query

# UI/スタイリング
npm install tailwindcss postcss autoprefixer
npm install lucide-react  # アイコンライブラリ

# フォーム
npm install react-hook-form @hookform/resolvers
npm install zod  # バリデーション

# ユーティリティ
npm install clsx  # クラス名の条件付き結合
npm install date-fns  # 日付操作

よく使うライブラリを一気に追加しましょう。

TailwindCSSのセットアップ

# TailwindCSS初期化
npx tailwindcss init -p
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
/* src/index.css に追加 */
@tailwind base;
@tailwind components;
@tailwind utilities;

これで、TailwindCSSが使えるようになりました。

プロジェクト構造の改善

// より実践的なプロジェクト構造
src/
├── components/          # 再利用可能コンポーネント
│   ├── ui/             # 基本UIコンポーネント
│   │   ├── Button.tsx
│   │   ├── Input.tsx
│   │   └── Modal.tsx
│   ├── layout/         # レイアウトコンポーネント
│   │   ├── Header.tsx
│   │   ├── Footer.tsx
│   │   └── Sidebar.tsx
│   └── common/         # 共通コンポーネント
│       ├── Loading.tsx
│       └── ErrorBoundary.tsx
├── pages/              # ページコンポーネント
│   ├── Home.tsx
│   ├── About.tsx
│   └── Contact.tsx
├── hooks/              # カスタムフック
│   ├── useAuth.ts
│   ├── useApi.ts
│   └── useLocalStorage.ts
├── store/              # 状態管理
│   ├── authStore.ts
│   └── appStore.ts
├── api/                # API関連
│   ├── client.ts
│   └── endpoints.ts
├── types/              # TypeScript型定義
│   ├── auth.ts
│   └── api.ts
├── utils/              # ユーティリティ関数
│   ├── format.ts
│   └── validation.ts
└── styles/             # スタイルファイル
    ├── globals.css
    └── components.css

実際のプロジェクトでは、この構造がおすすめです。

ルーティングの設定

// src/App.tsx - React Router設定
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import Layout from './components/layout/Layout';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';
import NotFound from './pages/NotFound';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<Layout />}>
            <Route index element={<Home />} />
            <Route path="about" element={<About />} />
            <Route path="contact" element={<Contact />} />
            <Route path="*" element={<NotFound />} />
          </Route>
        </Routes>
      </BrowserRouter>
    </QueryClientProvider>
  );
}

export default App;
// src/components/layout/Layout.tsx
import { Outlet } from 'react-router-dom';
import Header from './Header';
import Footer from './Footer';

export default function Layout() {
  return (
    <div className="min-h-screen flex flex-col">
      <Header />
      <main className="flex-1 container mx-auto px-4 py-8">
        <Outlet />
      </main>
      <Footer />
    </div>
  );
}

ルーティングとレイアウトの基本構造ができました。

状態管理の設定(Zustand)

// src/store/authStore.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

interface User {
  id: string;
  name: string;
  email: string;
}

interface AuthState {
  user: User | null;
  isAuthenticated: boolean;
  login: (email: string, password: string) => Promise<void>;
  logout: () => void;
  updateUser: (user: Partial<User>) => void;
}

export const useAuthStore = create<AuthState>()(
  persist(
    (set, get) => ({
      user: null,
      isAuthenticated: false,
      
      login: async (email: string, password: string) => {
        try {
          // API呼び出し
          const response = await fetch('/api/auth/login', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ email, password })
          });
          
          const user = await response.json();
          
          set({
            user,
            isAuthenticated: true
          });
        } catch (error) {
          console.error('Login failed:', error);
          throw error;
        }
      },
      
      logout: () => {
        set({
          user: null,
          isAuthenticated: false
        });
      },
      
      updateUser: (updates: Partial<User>) => {
        const currentUser = get().user;
        if (currentUser) {
          set({
            user: { ...currentUser, ...updates }
          });
        }
      }
    }),
    {
      name: 'auth-storage', // localStorage key
      partialize: (state) => ({ 
        user: state.user, 
        isAuthenticated: state.isAuthenticated 
      })
    }
  )
);

Zustandで状態管理も簡単にできます。

APIクライアントの設定

// src/api/client.ts
import { QueryClient } from '@tanstack/react-query';

const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3001/api';

class ApiClient {
  private baseURL: string;
  
  constructor(baseURL: string) {
    this.baseURL = baseURL;
  }
  
  private async request<T>(
    endpoint: string, 
    options: RequestInit = {}
  ): Promise<T> {
    const url = `${this.baseURL}${endpoint}`;
    
    const config: RequestInit = {
      headers: {
        'Content-Type': 'application/json',
        ...options.headers,
      },
      ...options,
    };
    
    // 認証トークンを自動付与
    const token = localStorage.getItem('auth-token');
    if (token) {
      config.headers = {
        ...config.headers,
        Authorization: `Bearer ${token}`,
      };
    }
    
    const response = await fetch(url, config);
    
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    return response.json();
  }
  
  get<T>(endpoint: string): Promise<T> {
    return this.request<T>(endpoint);
  }
  
  post<T>(endpoint: string, data: any): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'POST',
      body: JSON.stringify(data),
    });
  }
  
  put<T>(endpoint: string, data: any): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'PUT',
      body: JSON.stringify(data),
    });
  }
  
  delete<T>(endpoint: string): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'DELETE',
    });
  }
}

export const apiClient = new ApiClient(API_BASE_URL);
// src/hooks/useApi.ts - React Query と組み合わせ
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { apiClient } from '../api/client';

export function useUsers() {
  return useQuery({
    queryKey: ['users'],
    queryFn: () => apiClient.get('/users')
  });
}

export function useCreateUser() {
  const queryClient = useQueryClient();
  
  return useMutation({
    mutationFn: (userData: any) => apiClient.post('/users', userData),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['users'] });
    }
  });
}

API連携の基盤も整いました。

環境変数の設定

# .env.local
VITE_API_URL=http://localhost:3001/api
VITE_APP_NAME=My React App
VITE_VERSION=1.0.0

# .env.production
VITE_API_URL=https://api.myapp.com
VITE_APP_NAME=My React App
VITE_VERSION=1.0.0
// src/config/env.ts - 環境変数の型安全な使用
interface Environment {
  apiUrl: string;
  appName: string;
  version: string;
  isDevelopment: boolean;
  isProduction: boolean;
}

export const env: Environment = {
  apiUrl: import.meta.env.VITE_API_URL || 'http://localhost:3001/api',
  appName: import.meta.env.VITE_APP_NAME || 'React App',
  version: import.meta.env.VITE_VERSION || '1.0.0',
  isDevelopment: import.meta.env.DEV,
  isProduction: import.meta.env.PROD,
};

環境変数も型安全に管理できます。

ビルドと最適化

// vite.config.ts - 本番用最適化設定
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'

export default defineConfig({
  plugins: [react()],
  
  // パスエイリアス
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
      '@components': resolve(__dirname, 'src/components'),
      '@pages': resolve(__dirname, 'src/pages'),
      '@hooks': resolve(__dirname, 'src/hooks'),
      '@store': resolve(__dirname, 'src/store'),
      '@api': resolve(__dirname, 'src/api'),
      '@types': resolve(__dirname, 'src/types'),
      '@utils': resolve(__dirname, 'src/utils'),
    }
  },
  
  // ビルド最適化
  build: {
    sourcemap: true,
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          router: ['react-router-dom'],
          query: ['@tanstack/react-query'],
          ui: ['lucide-react']
        }
      }
    }
  },
  
  // 開発サーバー設定
  server: {
    port: 3000,
    open: true,
    proxy: {
      '/api': {
        target: 'http://localhost:3001',
        changeOrigin: true
      }
    }
  }
})

最適化設定もバッチリです。

これで、Viteを使ったモダンなReact開発環境が完成しました! 高速で柔軟な開発ができますね。

まとめ:今すぐ始めよう

2025年版のReactプロジェクトの始め方を解説しました。 最後に、重要なポイントをまとめます。

重要なポイント

1. create-react-appの現状

  • 開発・保守の停滞により、現在は推奨されない
  • 起動が遅く、古いツールチェインに依存
  • カスタマイズが困難で、モダンな開発体験を提供できない

2. 現代的な代替手段

Vite

  • 最高の開発体験(1-2秒起動、即座のHMR)
  • シンプルな設定、柔軟なカスタマイズ
  • SPA、学習、プロトタイプに最適

Next.js

  • フルスタックフレームワーク
  • SSR、SSG、SEO対応
  • 本格的なWebアプリケーションに最適

Remix

  • データ中心のアプローチ
  • Web標準準拠、Progressive Enhancement
  • フォーム処理が多いアプリに最適

T3 Stack

  • フルタイプセーフティ
  • エンタープライズ級の開発スタック
  • 大規模チーム開発に最適

選択指針

// プロジェクトタイプ別の推奨ツール
const recommendationMap = {
  学習: 'Vite',
  プロトタイプ: 'Vite',
  SPA: 'Vite + React Router',
  ビジネスサイト: 'Next.js',
  ブログ: 'Next.js',
  eコマース: 'Next.js',
  データ管理システム: 'Remix',
  企業アプリケーション: 'T3 Stack'
};

実践的なアドバイス

新規プロジェクト

  • まずはViteで始めて、要件に応じて他のツールを検討
  • TypeScriptを標準で使用
  • TailwindCSSでスタイリング効率化

既存プロジェクト

  • CRAプロジェクトの移行は段階的に検討
  • まずは新機能から新しいツールを試用
  • 移行コストと利益を慎重に比較

学習アプローチ

  • Viteで基本を学習
  • 要件に応じてNext.jsやRemixを習得
  • 最終的にT3 Stackで本格開発

最終的な推奨コマンド

初心者・学習目的

npm create vite@latest my-app -- --template react-ts

ビジネス・SEO重視

npx create-next-app@latest my-app --typescript --tailwind --app

データ重視・フォーム多用

npx create-remix@latest my-app

エンタープライズ・チーム開発

npm create t3-app@latest my-app

今後の動向

2025年注目の技術

  • Viteの更なる普及
  • Next.js App Routerの成熟
  • RemixとReact Routerの統合
  • React Server Componentsの標準化

新技術

  • Turbopack(Next.jsの新バンドラー)
  • SWC(Rustベースのコンパイラ)
  • React Compiler(自動最適化)
  • Suspense for Data Fetching

継続的な学習

  • 公式ドキュメント:各ツールの最新情報をチェック
  • コミュニティ:Discord、Reddit、Twitterで情報収集
  • 実践:小さなプロジェクトで新しいツールを試用
  • ベンチマーク:定期的にパフォーマンスを測定・比較

最後に

React開発環境は急速に進化しています。 create-react-appの時代は終わりました。

でも、それに代わる素晴らしい選択肢がたくさんあります。 プロジェクトの要件を明確にして、適切なツールを選びましょう。

より効率的で現代的なReact開発が実現できます。

みなさんの開発が、もっと楽しく効率的になりますように! ぜひ、新しいツールにチャレンジしてみてくださいね。

関連記事