ANTIGRAVITY LABEN
記事一覧/連携・プラグイン
連携・プラグイン/2026-04-01初級

Antigravity × React 完全入門ガイド:コンポーネント設計・Hooks・状態管理をAIで習得する

AntigravityでReact開発を加速する完全入門ガイド。コンポーネント設計・Hooks・useState/useReducer・状態管理ライブラリをAIアシストで爆速習得。実践コード例付き。

react3hooks2state-management2コンポーネント設計antigravity436コード生成

Reactは世界で最も広く使われているフロントエンドライブラリのひとつです。しかし「コンポーネントの分割粒度がわからない」「HooksのAPIが多くて混乱する」「状態管理ライブラリを何から選べばいいかわからない」といった悩みを持つ方も多いのではないでしょうか。

Antigravityを使えば、こうした学習ハードルを大幅に下げながら、実践的なReactアプリを短時間で構築できます。ここではAntigravityとReactを組み合わせた開発の基本から、Hooks・状態管理まで、具体的なコード例とともに丁寧に解説します。

なぜAntigravityでReact開発が加速するのか

ReactはJavaScriptの知識に加えて、JSX構文・コンポーネント設計・ライフサイクル・Hooksなど、習得すべき概念が多いライブラリです。Antigravityを活用することで、以下のような恩恵を受けられます。

  • コンポーネントの自動生成: 「ユーザーカードコンポーネントを作って」と伝えるだけで、propsの型定義からJSXまで一気に生成
  • リファクタリング提案: クラスコンポーネントを関数コンポーネント+Hooksへ自動変換
  • エラーの即時解決: TypeScriptの型エラーや実行時エラーをAIが原因分析&修正提案
  • ベストプラクティスの適用: useMemo・useCallback・Reactのレンダリング最適化を自動で組み込み

AntigravityのEditor ViewとReactの相性は抜群です。プロンプトを書くだけで、プロジェクトの既存コードベースを理解した上でコンポーネントを生成してくれるため、初心者でもすぐに実践的なコードが書けるようになります。

プロジェクトのセットアップ

まず、AntigravityでReactプロジェクトを作成する最もシンプルな方法を見ていきましょう。

# Vite + React + TypeScriptで新規プロジェクトを作成
npm create vite@latest my-react-app -- --template react-ts
cd my-react-app
npm install
npm run dev

プロジェクトを作成したら、AntigravityでフォルダをOpenします。Antigravityはプロジェクト構造を自動的に認識し、以降のコード生成の精度が格段に上がります。

次に、.antigravity/rules ファイルを作成して、プロジェクト固有のルールを設定しておくと、生成されるコードの品質がさらに向上します。

# .antigravity/rules
このプロジェクトはReact + TypeScriptで構築されています。
- 関数コンポーネントとHooksを使用してください(クラスコンポーネント禁止)
- PropsはTypeScriptのinterfaceで定義してください
- コンポーネントファイルは src/components/ に配置してください
- カスタムHooksは src/hooks/ に配置してください
- テストファイルは Vitest を使用してください

このルールファイルを設定するだけで、Antigravityが生成するコードが常にプロジェクトの規約に沿ったものになります。

コンポーネント設計の基本をAIで学ぶ

単純なコンポーネントの作成

Antigravityで最初のコンポーネントを作ってみましょう。チャット入力欄で「ユーザープロフィールカードコンポーネントを作成してください。名前・アバター画像・自己紹介文を表示します」と入力するだけで、以下のようなコードが生成されます。

// src/components/UserProfileCard.tsx
interface UserProfileCardProps {
  name: string;
  avatarUrl: string;
  bio: string;
}
 
export function UserProfileCard({ name, avatarUrl, bio }: UserProfileCardProps) {
  return (
    <div className="flex items-center gap-4 p-4 rounded-lg border bg-white shadow-sm">
      <img
        src={avatarUrl}
        alt={`${name}のアバター`}
        className="w-16 h-16 rounded-full object-cover"
      />
      <div>
        <h2 className="text-lg font-semibold text-gray-900">{name}</h2>
        <p className="text-sm text-gray-500 mt-1">{bio}</p>
      </div>
    </div>
  );
}

この生成されたコードのポイントは、TypeScriptのinterface定義が自動的に含まれていること、アクセシビリティのための alt 属性が設定されていること、そしてTailwind CSSのクラス名がすでに付与されていることです。

コンポーネントの分割粒度を相談する

コンポーネント設計で迷ったときも、Antigravityに相談できます。「このコンポーネントをさらに小さく分割すべきか判断してください」と聞くと、責任の分離・再利用性・可読性の観点から適切なアドバイスを得られます。

一般的な分割基準として、Antigravityはよく以下の観点を提示してくれます。

  • 100行を超えてきたら分割を検討する
  • ロジックとUIが混在している場合はカスタムHooksに分離
  • 同じパターンが3回以上繰り返されたらコンポーネント化

React Hooksの実践的な使い方

useState — 状態管理の基本

useState はReactの最も基本的なHookです。Antigravityでは「フォームのバリデーション付き入力コンポーネントを作成して」と伝えると、useState を使った実践的な実装が得られます。

// src/components/ValidatedInput.tsx
import { useState } from "react";
 
interface ValidatedInputProps {
  label: string;
  placeholder?: string;
  required?: boolean;
  minLength?: number;
  onValidChange: (value: string, isValid: boolean) => void;
}
 
export function ValidatedInput({
  label,
  placeholder,
  required = false,
  minLength = 0,
  onValidChange,
}: ValidatedInputProps) {
  const [value, setValue] = useState("");
  const [touched, setTouched] = useState(false);
 
  // バリデーションロジック
  const errorMessage = (() => {
    if (required && value.trim() === "") return "必須項目です";
    if (minLength > 0 && value.length < minLength) {
      return `${minLength}文字以上で入力してください`;
    }
    return null;
  })();
 
  const isValid = errorMessage === null;
 
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const newValue = e.target.value;
    setValue(newValue);
    if (touched) {
      onValidChange(newValue, isValid);
    }
  };
 
  const handleBlur = () => {
    setTouched(true);
    onValidChange(value, isValid);
  };
 
  return (
    <div className="flex flex-col gap-1">
      <label className="text-sm font-medium text-gray-700">
        {label}
        {required && <span className="text-red-500 ml-1">*</span>}
      </label>
      <input
        type="text"
        value={value}
        placeholder={placeholder}
        onChange={handleChange}
        onBlur={handleBlur}
        className={`px-3 py-2 border rounded-md text-sm ${
          touched && !isValid
            ? "border-red-400 focus:ring-red-300"
            : "border-gray-300 focus:ring-blue-300"
        } focus:outline-none focus:ring-2`}
      />
      {touched && errorMessage && (
        <p className="text-xs text-red-500">{errorMessage}</p>
      )}
    </div>
  );
}

このコードは、入力値・タッチ状態・バリデーション結果を管理する実践的なフォームコンポーネントです。Antigravityにこのコードを生成させた後、「エラーメッセージをアニメーション付きで表示したい」「パスワード強度チェックも追加して」など、追加要件を自然言語で伝えれば、AIが差分だけを編集してくれます。

useEffect — 副作用の管理

APIからデータをフェッチする場合など、副作用の処理には useEffect を使います。

// src/hooks/useGitHubUser.ts
import { useState, useEffect } from "react";
 
interface GitHubUser {
  login: string;
  name: string;
  avatar_url: string;
  bio: string;
  public_repos: number;
  followers: number;
}
 
interface UseGitHubUserResult {
  user: GitHubUser | null;
  loading: boolean;
  error: string | null;
}
 
export function useGitHubUser(username: string): UseGitHubUserResult {
  const [user, setUser] = useState<GitHubUser | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
 
  useEffect(() => {
    if (!username) return;
 
    let cancelled = false; // クリーンアップ用フラグ
    setLoading(true);
    setError(null);
 
    fetch(`https://api.github.com/users/${username}`)
      .then((res) => {
        if (!res.ok) throw new Error("ユーザーが見つかりません");
        return res.json();
      })
      .then((data: GitHubUser) => {
        if (!cancelled) {
          setUser(data);
          setLoading(false);
        }
      })
      .catch((err: Error) => {
        if (!cancelled) {
          setError(err.message);
          setLoading(false);
        }
      });
 
    // クリーンアップ: usernameが変わったら前のリクエストを無視
    return () => {
      cancelled = true;
    };
  }, [username]); // usernameが変わるたびに再実行
 
  return { user, loading, error };
}

このカスタムHooksは、GitHubのユーザー情報を非同期で取得し、ローディング・エラー状態もあわせて管理します。cancelled フラグによるクリーンアップ処理も自動的に含まれており、競合状態(Race Condition)を防いでいます。

AntigravityにこのようなHooksを生成させるときは、「TypeScriptで型安全にして」「エラーハンドリングを含めて」「クリーンアップ処理も入れて」と要件を明示すると、より堅牢なコードが得られます。

useReducer — 複雑な状態管理

複数の関連する状態がある場合、useReduceruseState より適していることがあります。Antigravityに「ショッピングカートの状態管理をuseReducerで実装して」と頼むと、以下のような実装が得られます。

// src/hooks/useCart.ts
import { useReducer } from "react";
 
interface CartItem {
  id: string;
  name: string;
  price: number;
  quantity: number;
}
 
interface CartState {
  items: CartItem[];
  total: number;
}
 
type CartAction =
  | { type: "ADD_ITEM"; payload: Omit<CartItem, "quantity"> }
  | { type: "REMOVE_ITEM"; payload: { id: string } }
  | { type: "UPDATE_QUANTITY"; payload: { id: string; quantity: number } }
  | { type: "CLEAR_CART" };
 
function cartReducer(state: CartState, action: CartAction): CartState {
  switch (action.type) {
    case "ADD_ITEM": {
      const existing = state.items.find((item) => item.id === action.payload.id);
      const newItems = existing
        ? state.items.map((item) =>
            item.id === action.payload.id
              ? { ...item, quantity: item.quantity + 1 }
              : item
          )
        : [...state.items, { ...action.payload, quantity: 1 }];
      return {
        items: newItems,
        total: newItems.reduce((sum, item) => sum + item.price * item.quantity, 0),
      };
    }
    case "REMOVE_ITEM": {
      const newItems = state.items.filter((item) => item.id !== action.payload.id);
      return {
        items: newItems,
        total: newItems.reduce((sum, item) => sum + item.price * item.quantity, 0),
      };
    }
    case "UPDATE_QUANTITY": {
      const newItems = state.items.map((item) =>
        item.id === action.payload.id
          ? { ...item, quantity: Math.max(0, action.payload.quantity) }
          : item
      ).filter((item) => item.quantity > 0);
      return {
        items: newItems,
        total: newItems.reduce((sum, item) => sum + item.price * item.quantity, 0),
      };
    }
    case "CLEAR_CART":
      return { items: [], total: 0 };
    default:
      return state;
  }
}
 
const initialState: CartState = { items: [], total: 0 };
 
export function useCart() {
  const [state, dispatch] = useReducer(cartReducer, initialState);
 
  return {
    items: state.items,
    total: state.total,
    addItem: (item: Omit<CartItem, "quantity">) =>
      dispatch({ type: "ADD_ITEM", payload: item }),
    removeItem: (id: string) => dispatch({ type: "REMOVE_ITEM", payload: { id } }),
    updateQuantity: (id: string, quantity: number) =>
      dispatch({ type: "UPDATE_QUANTITY", payload: { id, quantity } }),
    clearCart: () => dispatch({ type: "CLEAR_CART" }),
  };
}

このパターンのメリットは、状態変化のロジックがすべて cartReducer に集約されていることです。テストを書きやすく、バグの原因特定も容易になります。

React状態管理のさらに深い実装については、Antigravity × Storybook でコンポーネント駆動開発を加速するでもコンポーネントのテスト手法と合わせて解説しています。

Context APIで状態を共有する

複数のコンポーネント間で状態を共有したい場合、Props Drillingを避けるためにContext APIを活用します。

// src/context/ThemeContext.tsx
import { createContext, useContext, useState, ReactNode } from "react";
 
type Theme = "light" | "dark";
 
interface ThemeContextValue {
  theme: Theme;
  toggleTheme: () => void;
}
 
const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);
 
export function ThemeProvider({ children }: { children: ReactNode }) {
  const [theme, setTheme] = useState<Theme>("light");
 
  const toggleTheme = () => {
    setTheme((prev) => (prev === "light" ? "dark" : "light"));
  };
 
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      <div className={theme === "dark" ? "dark" : ""}>{children}</div>
    </ThemeContext.Provider>
  );
}
 
// カスタムHooksでContextを安全に使う
export function useTheme(): ThemeContextValue {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error("useTheme は ThemeProvider の内部で使用してください");
  }
  return context;
}

Antigravityにこのパターンを生成させるとき、「ThemeProviderの外でuseThemeを使ったときのエラーハンドリングも含めて」と一言添えるだけで、安全なカスタムHooksが自動生成されます。

よくあるエラーと対処法

Reactを使っていると必ずといっていいほど遭遇するエラーをまとめましました。これらはAntigravityのチャットに貼り付けるだけで、原因と修正方法を即座に教えてくれます。

エラー1: Warning: Each child in a list should have a unique "key" prop

リストのレンダリングで key プロパティが不足している場合に発生します。AntigravityはMapで生成するリストに key を自動的に追加しますが、手書きコードでは忘れがちです。key には配列のインデックスより、データの一意なIDを使うことを推奨します。

エラー2: Cannot update a component while rendering a different component

レンダリング中に別コンポーネントのstateを更新しようとすると発生します。useEffect の中で状態更新するか、コールバック経由で親に通知する設計に変更することで解決できます。

エラー3: Too many re-renders

useStateuseEffect の依存配列の設定ミスで無限レンダリングが発生します。Antigravityに「この useEffect の依存配列が正しいか確認して」と伝えると、ESLintルール exhaustive-deps に準拠した正しい依存配列を提案してくれます。

Antigravityのチャット欄にエラーメッセージをそのままペーストし、「このエラーの原因と修正方法を教えてください」と尋ねるだけで、多くのケースで即解決できます。詳しいデバッグ手法については、Antigravity AI デバッグ活用ガイドを参考にしてください。

コンポーネントのパフォーマンス最適化

アプリが大きくなると、不要な再レンダリングがパフォーマンスに影響してきます。Antigravityに「このコンポーネントのパフォーマンスを最適化して」と伝えると、以下のような改善を自動的に提案してくれます。

// 最適化前
function ExpensiveList({ items, onSelect }: Props) {
  // itemsが変わるたびにフィルタリングが再実行される
  const filtered = items.filter((item) => item.active);
 
  // 関数が毎回新しく作られる
  const handleSelect = (id: string) => {
    onSelect(id);
  };
 
  return (
    <ul>
      {filtered.map((item) => (
        <ListItem key={item.id} item={item} onSelect={handleSelect} />
      ))}
    </ul>
  );
}
 
// 最適化後(Antigravityが自動で提案)
import { useMemo, useCallback, memo } from "react";
 
const ListItem = memo(function ListItem({
  item,
  onSelect,
}: {
  item: Item;
  onSelect: (id: string) => void;
}) {
  return (
    <li onClick={() => onSelect(item.id)} className="cursor-pointer py-2">
      {item.name}
    </li>
  );
});
 
function ExpensiveList({ items, onSelect }: Props) {
  // itemsが変わったときだけフィルタリングを再実行
  const filtered = useMemo(
    () => items.filter((item) => item.active),
    [items]
  );
 
  // onSelectが変わったときだけ関数を再生成
  const handleSelect = useCallback(
    (id: string) => {
      onSelect(id);
    },
    [onSelect]
  );
 
  return (
    <ul>
      {filtered.map((item) => (
        <ListItem key={item.id} item={item} onSelect={handleSelect} />
      ))}
    </ul>
  );
}

memouseMemouseCallback の使い分けもAntigravityに聞けば、コンテキストに合わせた使用場面を具体的に説明してくれます。

EditorのAI機能をフル活用する方法については、Google Antigravity Editor View 入門 — AI搭載コードエディタの完全ガイドでより詳しく解説しています。

全体を振り返って

AntigravityとReactを組み合わせることで、コンポーネント設計・Hooks・状態管理といったReactの主要概念を実践しながら素早く習得できます。ここでは以下のポイントを解説しました。

  • Antigravityでのプロジェクトセットアップと .antigravity/rules の設定
  • useStateuseEffectuseReducer の実践的な使い方
  • Context APIを使ったグローバル状態管理
  • memouseMemouseCallback によるパフォーマンス最適化

Antigravityはコードを生成するだけでなく、「なぜこの実装が良いのか」を説明してくれる優れた学習ツールでもあります。コードに迷ったら気軽にチャットで質問してみてください。

React開発をさらに深めたい方には、Antigravity × Storybook でコンポーネント駆動開発を加速するもあわせておすすめです。コンポーネントの分離・カタログ化・テスト自動化まで体系的に学べます。また、AIコード編集の効率をさらに上げたい方は、Antigravity インラインチャット(Cmd+I)完全活用ガイドもぜひご参照ください。

なお、AntigravityのEditor Viewをより深く使いこなすヒントは、Antigravity Editor 上級カスタマイズガイドでプロ向けの設定まで網羅されています。

本記事の内容

シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

連携・プラグイン2026-04-10
Antigravity × XState v5 ステートマシン設計 — 複雑なUI状態遷移・ワークフロー・フォームバリデーションを型安全に実装する
XState v5とAntigravityを組み合わせ、複雑なUI状態遷移・マルチステップフォーム・非同期ワークフローを型安全に設計・実装する上級テクニックを実践コード付きで解説します。
連携・プラグイン2026-03-25
Antigravity × Storybook でコンポーネント駆動開発を加速する — AIが支援するUI設計・テスト・ドキュメント自動化
Antigravity IDEとStorybookを組み合わせたコンポーネント駆動開発(CDD)の実践ガイド。AIによるStory自動生成、ビジュアルテスト、ドキュメント自動化まで解説します。
連携・プラグイン2026-07-15
無人ランで作業フォルダが突然『別の人の持ち物』になる — 所有者ドリフトを検知して書ける場所へ逃がす
数週間緑だった無人スケジュールが、ある朝 git config を書けずに止まりました。原因は永続作業フォルダの所有者ドリフト。存在チェックでは通り書き込みだけが弾かれる罠を切り分け、書込可否を実測して別の場所へ逃がすプリフライトを実装まで残します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →