react19-patterns について
React Compilerを有効にしたReact 19プロジェクト向けのコーディングスキルです。Contextと`use()`のパターン、コンパイラーによる最適化、ViewTransitionとSuspenseの境界設定を扱います。
主な機能
- 01React 19のContextプロバイダー構文
- 02`useContext()`の代わりに`use()`を使用
- 03コンパイラーのメモ化を活用
- 04不要な手動最適化を回避
- 05ViewTransitionとSuspenseの調整
活用シーン
- 01React 19コンポーネントでのContext利用
- 02冗長な手動メモ化の削除
- 03Suspenseによるハイドレーション不一致の防止
- 04手動最適化前のパフォーマンス計測
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ qingqishi/ shiqingqi.com --skill react19-patternsインストール後、Claude Code で/react19-patternsを入力して読み込まれたか確認します。
詳細
React 19 のパターン
概要
このプロジェクトでは、React Compiler を有効にした React 19 を使用しています。これにより、特に Context や最適化に関する React コードの書き方が変わります。
React 19 の Context パターン
短縮構文を使用する
React 19 では、Context プロバイダーの短縮構文が導入されています。
✅ 正しい例(React 19):
<MyContext value={someValue}>
<ChildComponents />
</MyContext>
❌ 誤った例(古いパターン):
<MyContext.Provider value={someValue}>
<ChildComponents />
</MyContext.Provider>
useContext() の代わりに use() フックを使用する
React 19 では、コンテキストを使用するための use() フックが導入されています。
✅ 正しい例(React 19):
import { use } from "react";
import { MyContext } from "./MyContext";
function MyComponent() {
const value = use(MyContext);
return <div>{value}</div>;
}
❌ 誤った例(古いパターン):
import { useContext } from "react";
import { MyContext } from "./MyContext";
function MyComponent() {
const value = useContext(MyContext);
return <div>{value}</div>;
}
React Compiler が有効
手動でのメモ化は不要
React Compiler はコンポーネントを自動的に最適化し、メモ化を処理します。手動でメモ化するパターンは使用しないでください。
✅ 正しい例(React Compiler が処理):
function MyComponent({ items }) {
// React Compiler automatically memoizes this computation
const filteredItems = items.filter((item) => item.active);
// React Compiler automatically stabilizes this function reference
const handleClick = (id) => {
console.log(id);
};
return (
<div>
{filteredItems.map((item) => (
<button key={item.id} onClick={() => handleClick(item.id)}>
{item.name}
</button>
))}
</div>
);
}
❌ 誤った例(手動でのメモ化は不要):
import { useMemo, useCallback, memo } from "react";
function MyComponent({ items }) {
// ❌ Don't use useMemo - React Compiler handles this
const filteredItems = useMemo(
() => items.filter((item) => item.active),
[items],
);
// ❌ Don't use useCallback - React Compiler handles this
const handleClick = useCallback((id) => {
console.log(id);
}, []);
return <div>...</div>;
}
// ❌ Don't use memo() - React Compiler handles this
export default memo(MyComponent);
React 19 の ViewTransition と Suspense のパターン
ハイドレーションの問題
<ViewTransition> で Suspense 境界を含むコンテンツをラップすると、一部の子要素が Suspense 内にあり、ほかの子要素がそうでない場合に、ハイドレーションエラーが発生することがあります。
エラーメッセージ:
A tree hydrated but some attributes of the server rendered HTML didn't match the client properties.
This won't be patched up. This can happen if a SSR-ed Client Component used...
Specifically: style={{view-transition-name:"_T_0_"}}
根本原因:
- ViewTransition は、トランジションが開始されたときにのみ
view-transition-nameスタイルを適用する「ジャストインタイム」方式を使用します - SSR のハイドレーション中に、Suspense を含まない子要素からコンテンツが表示されると、ViewTransition が有効になります
- その結果、サーバーの HTML にはなかったスタイルが、ハイドレーション中にクライアント側で適用されます
- React が不一致を検出し、ハイドレーションの警告を記録します
解決策:Suspense 境界を統一する
✅ 正しい例(すべてのコンテンツを Suspense 内に配置):
<ViewTransition>
<Suspense fallback={<HeaderSkeleton />}>
<Header />
</Suspense>
<Suspense fallback={null}>{children}</Suspense>
</ViewTransition>
❌ 誤った例(Suspense 内外が混在):
<ViewTransition>
<Suspense fallback={<HeaderSkeleton />}>
<Header />
</Suspense>
{children} {/* NOT in Suspense - causes hydration error! */}
</ViewTransition>
別の方法(ViewTransition の外側に Suspense を配置):
<Suspense fallback={<LoadingSkeleton />}>
<ViewTransition>
<Header />
{children}
</ViewTransition>
</Suspense>
注:この方法では、すべてのコンテンツが同じローディング状態になります。Header と子要素を個別に読み込む必要がある場合は、望ましくないことがあります。
この修正で解決する理由
すべての子要素を Suspense 境界でラップすると、次のようになります。
- コンテンツの表示が React の Suspense 機構を通じて調整されます
- ハイドレーション中に ViewTransition が早期に有効になることを防ぎます
- サーバーとクライアントのレンダリングの一貫性が保たれます
- ハイドレーションの不一致が発生しなくなります
主なルール
- Context の短縮構文:
<Context.Provider value={...}>ではなく、常に<Context value={...}>を使用します - use() フック:
useContext(Context)ではなく、常にuse(Context)を使用します - useMemo は使用しない:React Compiler が負荷の高い計算を自動的にメモ化します
- useCallback は使用しない:React Compiler が関数の参照を自動的に安定させます
- memo() は使用しない:React Compiler がコンポーネントの再レンダリングを自動的に最適化します
- コンパイラーを信頼する:手動のパターンではなく、React Compiler に最適化を任せます
- ViewTransition と Suspense:ViewTransition を Suspense と併用する場合は、ハイドレーションエラーを防ぐため、すべての子要素を Suspense 境界内に配置します
手動での最適化が必要になる場合
まれに、手動での最適化が必要になることがあります。
- 安定した参照を必要とする外部ライブラリとの連携
- パフォーマンスのプロファイリングで、React Compiler が検出できない特定の問題が確認された場合
手動で最適化を追加する前に、必ずプロファイリングを行ってください。 React Compiler は非常に効果的です。