> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# React 18 から 19 へのアップグレード用プレイブックを作成する

export const UseCaseHero = ({title, description, prompt, category, features, devinUrl, agent, intent, playbookId, type}) => {
  const encodedPrompt = encodeURIComponent(prompt || '');
  const tag = 'docs-use-case-gallery';
  const utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=hero-cta';
  const agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  const devinHref = type === 'schedule' ? 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + (prompt ? '&prompt=' + encodedPrompt : '') : type === 'review' ? 'https://app.devin.ai/review?' + utm : agent === 'ada' ? 'https://app.devin.ai/search?' + utm + '&noSubmit=true' + (prompt ? '&prompt=' + encodedPrompt : '') : devinUrl ? devinUrl.includes('?') ? devinUrl + '&' + utm + agentParams : devinUrl + '?' + utm + agentParams : prompt ? 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encodedPrompt : 'https://app.devin.ai/?' + utm + agentParams;
  const buttonLabel = type === 'schedule' ? 'Schedule in Devin ↗' : type === 'review' ? 'Set Up Devin Review ↗' : agent === 'advanced' ? 'Try in Devin ↗' : agent === 'dana' ? 'Try in Dana ↗' : agent === 'ada' ? 'Try in Ask Devin ↗' : 'Try in Devin ↗';
  const featureList = features ? features.split(',').map(f => f.trim()) : [];
  return <div className="uc-hero">
      <div className="uc-hero-inner">
        <div className="uc-hero-left">
          <h1 className="uc-hero-title">{title}</h1>
          <p className="uc-hero-desc">{description}</p>
          <div>
            <a href={devinHref} target="_blank" rel="noopener noreferrer" className="try-in-devin-btn">
              {buttonLabel}
            </a>
          </div>
        </div>
        <div className="uc-hero-meta">
          <div className="uc-meta-item">
            <span className="uc-meta-label">Author</span>
            <span className="uc-meta-value">Cognition</span>
          </div>
          <div className="uc-meta-item">
            <span className="uc-meta-label">Category</span>
            <span className="uc-meta-value">{category}</span>
          </div>
          {featureList.length > 0 && <div className="uc-meta-item">
              <span className="uc-meta-label">Features</span>
              <span className="uc-meta-value">{featureList.join(', ')}</span>
            </div>}
        </div>
      </div>
    </div>;
};

export const PromptBlock = ({children, type, agent, intent, playbookId}) => {
  var utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=prompt-block';
  var tag = 'docs-use-case-gallery';
  var agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  var label = type === 'schedule' ? 'Schedule in Devin' : type === 'playbook' ? 'Create Playbook' : type === 'knowledge' ? 'Add to Knowledge' : agent === 'advanced' ? 'Try in Devin' : agent === 'dana' ? 'Try in Dana' : agent === 'ada' ? 'Try in Ask Devin' : 'Try in Devin';
  var buildUrl = function (text) {
    var encoded = encodeURIComponent(text);
    if (type === 'schedule') return 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + '&prompt=' + encoded;
    if (type === 'playbook') return 'https://app.devin.ai/settings/playbooks/create?' + utm + '&body=' + encoded;
    if (type === 'knowledge') return 'https://app.devin.ai/knowledge?' + utm + '&body=' + encoded;
    if (agent === 'ada') return 'https://app.devin.ai/search?' + utm + '&noSubmit=true&prompt=' + encoded;
    return 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encoded;
  };
  const ref = React.useRef(null);
  const [href, setHref] = React.useState('#');
  React.useEffect(() => {
    if (!ref.current) return;
    var codeEl = ref.current.querySelector('pre code');
    if (codeEl) {
      var text = codeEl.textContent.trim();
      if (text) setHref(buildUrl(text));
    }
    var header = ref.current.querySelector('[data-component-part="code-block-header"]');
    if (header && !header.querySelector('.prompt-block-devin-link')) {
      var link = document.createElement('a');
      link.href = href;
      link.target = '_blank';
      link.rel = 'noopener noreferrer';
      link.className = 'prompt-block-devin-link';
      link.style.cssText = 'display:inline-flex;align-items:center;gap:6px;text-decoration:none;color:#fff;font-size:11px;font-weight:500;padding:4px 10px;border-radius:6px;white-space:nowrap;background:#317CFF;transition:background 0.2s;margin-left:8px;';
      link.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg> ' + label;
      link.onmouseenter = function () {
        link.style.background = '#2968D9';
      };
      link.onmouseleave = function () {
        link.style.background = '#317CFF';
      };
      header.appendChild(link);
    }
    var existingLink = ref.current.querySelector('.prompt-block-devin-link');
    if (existingLink && href !== '#') existingLink.href = href;
  });
  return <div className="prompt-block" ref={ref}>{children}</div>;
};

<UseCaseHero title="React 18 から 19 へのアップグレードプレイブックを作成" description="公式の React 19 アップグレードガイドを、コードベースに対応させた段階的なプレイブックに落とし込みます。" prompt="https://react.dev/blog/2024/04/25/react-19-upgrade-guide にある React 19 アップグレードガイドと自社の React アプリを確認してください。すべての破壊的変更がコードのどこに対応するかをマッピングした移行プレイブックを作成してください。削除された API を使用しているファイル、新しい JSX トランスフォームが必要な箇所を特定し、アップグレードをどのように段階的に進めれば少しずつリリースできるかを示してください。" category="移行" features="高度, プレイブック" agent="advanced" intent="create" />

<div className="uc-detail-wrapper">
  <Tip>手動でのセットアップが面倒ですか？このページのリンクを Devin のセッションに貼り付けて、すべてのセットアップを依頼してください。</Tip>

  <Steps>
    <Step title="React 19 アップグレードガイドを使って Devin に指示する">
      React 19 では、ref の扱い、コンテキストの利用方法、TypeScript の型、廃止されたレガシー API などに、後方互換性を破壊する変更が導入されています。[公式アップグレードガイド](https://react.dev/blog/2024/04/25/react-19-upgrade-guide)にはすべての変更が記載されていますが、難しいのはそれらを *自分たちの* コードに対応付けることです。自分でガイドを読み、すべてのコンポーネントを精査する代わりに、ガイドとコードベースの両方を Devin に渡して、実際のファイルを対象にしたプレイブックを生成させましょう。

      [Devin のホームページ](https://app.devin.ai/?utm_source=docs\&utm_medium=use-case-gallery)から新しい Devin セッションを開き、アップグレードガイドの URL と必要な内容を含むプロンプトを貼り付けてください:

      <PromptBlock agent="advanced">
        ```txt Build React 18→19 upgrade playbook theme={null}
        We're upgrading our React app from v18 to v19.
        Here's the official upgrade guide:
        https://react.dev/blog/2024/04/25/react-19-upgrade-guide

        Build a migration playbook specific to our codebase:
        - Install react@18.3 first and fix every deprecation warning
          before touching v19
        - Find all uses of forwardRef and plan the ref-as-prop migration
        - Identify components using the legacy Context API (contextTypes,
          getChildContext) that need conversion to createContext
        - Flag any string ref usage or legacy lifecycle methods
        - List TypeScript files that need updated ref types
          (e.g., removing RefObject in favor of RefObject | null)
        - Order the steps so we can ship incrementally — deprecation
          fixes first, then API removals, then new features
        - Include a validation step after each phase
        ```
      </PromptBlock>
    </Step>

    <Step title="コードベース固有のコンテキストを付与する">
      Devin は、あなたのリポジトリのアーキテクチャを自動的に理解するために [DeepWiki](/ja/work-with-devin/deepwiki) を使用します。また、React 19 に関するオンライン情報源 ― 公式アップグレードガイド、ブログ記事、ライブラリの変更履歴 ― も参照し、そこで得た内容を直接プレイブックに取り込むことができます。

      プレイブックの精度をさらに高めるために、移行で影響を受けるパターンについて Devin に伝えてください:

      * *"`src/components/ui/` 配下の 23 個のコンポーネントで `forwardRef` を使っています — これらは私たちのデザインシステムのプリミティブです"*
      * *"`src/legacy/` には、まだ文字列 refs と `componentWillMount` を使っているクラスコンポーネントが 4 つあります"*
      * *"組織内の他のリポジトリ (例: `acme/design-system`, `acme/admin-dashboard`) を確認して、すでに React 19 への移行を始めているかどうかを確認し、そこで確立されたパターンがあれば再利用してください"*

      依存ライブラリごとに React 19 互換性ガイド (例: React Router、React Hook Form、あるいは使用している UI ライブラリ) が用意されている場合は、それらの URL もプロンプトに貼り付けてください — Devin がすべて読み込み、破壊的変更を照らし合わせて確認します。
    </Step>

    <Step title="コードベースごとのプレイブックを確認する">
      Devin は React 19 のアップグレードガイドを最初から最後まで読み込み、すべての後方互換性のない変更を、[DeepWiki](/ja/work-with-devin/deepwiki) を通じてあなたのコードベースと照合し、対象ファイル、複雑さの見積もり、検証ステップを含むフェーズごとのプレイブックを作成します。

      ```markdown theme={null}
      # React 18 → 19 移行プレイブック

      ## フェーズ1: React 18.3へのアップグレードと非推奨警告の修正 (S)
      - npm install react@18.3 react-dom@18.3
      - アプリを実行し、コンソールの非推奨警告をすべて修正する:
        - src/legacy/OldModal.tsx、src/legacy/OldTooltip.tsx の文字列 ref を削除する
        - src/legacy/DropdownMenu.tsx の ReactDOM.findDOMNode を置き換える
      - テストスイートを実行してリグレッションがないことを確認する
      - 検証: 開発コンソールに非推奨警告がゼロ、すべてのテストが通過

      ## フェーズ2: forwardRef から ref-as-prop への移行 (M)
      - src/components/ui/ 内の23コンポーネントから forwardRef ラッパーを削除する:
        - Button.tsx、Input.tsx、Select.tsx、TextArea.tsx（使用頻度高）
        - Modal.tsx、Popover.tsx、Tooltip.tsx（使用頻度中）
        - +16コンポーネント（全リストは下記）
      - forwardRef でラップする代わりに ref を通常の prop として渡す
      - TypeScript 型を更新: RefObject<T> を RefObject<T> | null に変更する
      - 新しい React 19 の ref セマンティクスに合わせて src/types/refs.d.ts を更新する
      - 検証: すべての ref フォワーディングコンポーネントがレンダリングされ、フォーカス管理が機能する

      ## フェーズ3: 非推奨 API の削除 (M)
      - レガシー Context（contextTypes/getChildContext）を以下で置き換える:
        - src/legacy/ThemeProvider.tsx → すでに createContext を使用（変更不要）
        - src/legacy/LocaleContext.tsx → createContext パターンに変換する
      - 12ファイルから propTypes を削除する（TypeScript がバリデーションを担当）
      - 関数コンポーネントから defaultProps を削除する（JS のデフォルト値を使用）
      - 検証: Context の値が正しく伝播し、実行時警告がない

      ## フェーズ4: データフェッチと Suspense パターンの更新 (L)
      - src/components/layouts/ の Suspense 境界を確認する
      - フォールバック動作の変更に依存するコンポーネントを更新する
      - 新しい Suspense セマンティクスで src/routes/ の遅延ロードルートをテストする
      - 検証: すべての遅延ルートが読み込まれ、ローディング状態が正しくレンダリングされる

      ## フェーズ5: React 19 のインストールと新機能の採用 (M)
      - npm install react@19 react-dom@19
      - src/hooks/useFormField.ts の useFormState を useActionState に置き換える
      - react-dom のインポートを更新: ReactDOM.render → すでに createRoot を使用
      - 新しい JSX トランスフォームが未有効の場合は有効化する
      - 検証: テストスイート全体が通過し、アプリがエラーなく動作する

      ## フェーズ6: サードパーティライブラリの更新 (L)
      - react-hook-form → v8 にアップグレード（React 19 対応）
      - @radix-ui/react-* → 最新版にアップグレード（ref-as-prop サポート）
      - react-router-dom → v6.4+ との互換性を確認する
      - 検証: フォームが正しく送信され、UI プリミティブがレンダリングされ、ルーティングが機能する

      ## リスク
      - forwardRef の削除は変更量が最も多い — 23コンポーネント、多くが他チームによって使用されている
      - TypeScript の ref 型変更により null 安全性の問題が表面化する可能性がある
      - react-hook-form v8 には独自の破壊的変更がある — フォームのバリデーションを十分にテストすること
      ```

      このプレイブックは実際の移行作業そのものではなく、あくまで計画です。チームでレビューし、フェーズやスコープを調整したうえで、どのように実行するかを決定してください。
    </Step>

    <Step title="実行とスケール">
      プレイブックの内容が問題なさそうであれば保存し、セッションに添付してフェーズごとに実行します:

      <PromptBlock>
        ```txt theme={null}
        React 19 への移行プレイブックを実行してください。
        フェーズ 1（React 18.3 へのアップグレードと非推奨警告の修正）から
        移行プレイブックの実行を開始してください。各フェーズの後に、
        dev サーバーとフルテストスイートを実行してください。すべてが
        パスした場合にのみ次のフェーズに進んでください。完了したら PR を作成してください。
        ```
      </PromptBlock>

      **リポジトリ横断でスケール** — 同じアップグレードが必要な複数の React アプリがある場合は、[managed Devins](/ja/work-with-devin/advanced-capabilities#managed-devins) を使って、保存したプレイブックをそれらすべてで並列実行するよう Devin に依頼してください。
    </Step>
  </Steps>
</div>
