mcpField
R
react

react

github.com/lobehub開発83.6k5.7k 回インストール今日更新
リポジトリ

react について

プロジェクト開発者向けのReactコンポーネント作成ガイドです。StyleXの移行、コンポーネント選択、状態管理、描画性能に関する規約をまとめています。

主な機能

  1. 01StyleXのスタイル作成と移行
  2. 02UIコンポーネント選択の優先順位
  3. 03状態の所有者と分割境界
  4. 04Popoverのクローズ動作
  5. 05描画性能とメモ化の規則
  6. 06レイアウトコンポーネントの規約

活用シーン

  1. 01既存コンポーネントのStyleX移行
  2. 02適切な基本UIコンポーネントの選択
  3. 03状態と再利用境界の見直し
  4. 04ナビゲーション後のPopover終了確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/lobehub/lobehub --skill react

インストール後、Claude Code で/reactを入力して読み込まれたか確認します。

同梱ファイルreferences/layout-kit.md

詳細

React コンポーネントの記述ガイド

スタイリング

シナリオアプローチ
すでに StyleX を使用しているファイル、および新しい SPA のスタイルstylex.create + @lobehub/ui/stylex/cssVar.stylex / @lobehub/ui/stylex/media.stylex。SPA コンパイラーは plugins/vite/stylex.ts(@stylexjs/unplugin、プレフィックスは lh)です。これらのトークンモジュールをアプリにコピーしないでください。
既存のスタイルがまだ移行されていない場合createStaticStyles + cssVar.*(ゼロランタイム、モジュールレベル)
シンプルな単発のスタイルインラインの style 属性
真に動的なスタイル(readableColor/chroma のような JS の色関数)createStyles + token — 最後の手段
StyleX
  • 新しいコードでは、@lobehub/ui から createStaticStyles / createStyles / css / keyframes / createGlobalStyle / injectGlobal をインポートしないでください(stylex-migration/no-emotion-styles)。引き続きこれらを使用しているファイルは scripts/stylexMigration/legacyFiles.json に記載されています。ファイルを移行した後は、bun run stylex:migration --prune-legacy を実行してください。エントリーを追加してはいけません。
  • ファイル全体を一度に移行してください。StyleX のロングハンドルールは詳細度が高く(.x:not(#\#))、同じ要素の emotion クラスより優先されますが、StyleX のショートハンドルールはそうではありません。そのため、一部だけ移行した要素ではプロパティごとに解決されます。
  • 呼び出し元の className / style も転送する要素では、@/styles/sx の {...sx([styles.root, active && styles.active], className, style)} を使用してください。stylex.props を className の隣に展開すると、@stylexjs/no-conflicting-props エラーになります。
  • 呼び出し元がスタイルを上書きできるコンポーネントでは、xstyle?: StyleXStyles を受け取り、sx / stylex.props 配列の最後に渡してください。外部から指定した通常の className では StyleX ルールを上書きできません。@lobehub/ui コンポーネントにクラスを渡す場合(className、classNames)は機能します。lobe-ui の CSS は @layer lobe-ui 内にあるためです。
  • 値は @stylexjs/valid-styles に従います。複数値のショートハンド(margin: '0 8px' → marginBlock / marginInline)は使わず、flex には文字列を指定します(flex: '1')。
  • background、animation、border および border{Top,Right,Bottom,Left} のショートハンドは、どのような値でも(border: 'none' を含め)エラーなしでクラスが一切生成されません。ロングハンドを記述してください。background のショートハンドを置き換える場合は、backgroundColor(および backgroundImage: 'none')、animationName / animationDuration / …、borderWidth / borderStyle / borderColor を使用します。
  • 開発環境で移行を確認するには、DevDock のスナップショットヘルパーを使用します。移行したページで __lobeStyleSnapshot.capture('<name>', '<root selector>') を実行し、ファイルを元に戻して(git stash push -- <path>)、再読み込みし、__lobeStyleSnapshot.compare('<name>') を実行してから git stash pop を実行します。各ペアは [captured, current](ここでは [migrated, original])を読み込みます。追跡対象の計算済みスタイル、ボックス(ルートからの相対位置)、またはテキストに差異がある要素と ::before / ::after を一覧表示します。リストが空であれば、それらが一致していることを意味しますが、ホバー、フォーカス、閉じたダイアログを確認したという意味ではありません。移行した各状態を開いて、それも比較してください。ウィンドウサイズを維持し、ルート内のスクロール位置をすべて先頭に戻し、比較対象の領域からポインターを移動してください。
  • bun run stylex:migration --list <A|B|C|D> は、移行の難易度別にファイルを一覧表示します。A はフラット、B は自身の疑似クラス、C は子孫 / 祖先との結合(stylex.defaultMarker() と stylex.when.ancestor() または xstyle を使用)、D はタグ / サードパーティ DOM セレクター(スコープ付きの通常の CSS)です。

コンポーネントの優先順位

  1. src/components — プロジェクト固有の再利用可能なコンポーネント
  2. @lobehub/ui/base-ui — ヘッドレスプリミティブ。コンポーネントがここにある場合は、こちらを使用してください。同じ名前のルートエクスポートをインポートしてはいけません。
  3. @lobehub/ui — 高レベルのコンポーネント / antd をラップするコンポーネント(base-ui に同等のものがない場合のみ)
  4. antd — base-ui と @lobehub/ui のルートエクスポートのどちらにもない場合のみ
  5. カスタム実装 — 真に最後の手段

利用可能なコンポーネントが不明な場合は、既存のコードを検索するか、node_modules/@lobehub/ui/es/index.mjs と node_modules/@lobehub/ui/es/base-ui/ を確認してください。

@lobehub/ui/base-ui — これらは常にこちらを優先してください
コンポーネントインポート
Alert(および AlertProps)import { Alert, type AlertProps } from '@lobehub/ui/base-ui';
Select(および SelectProps、SelectOption)import { Select } from '@lobehub/ui/base-ui';
Modal(命令型 API)import { createModal, confirmModal, useModalContext, type ModalInstance } from '@lobehub/ui/base-ui';
DropdownMenuimport { DropdownMenu } from '@lobehub/ui/base-ui';
ContextMenuimport { ContextMenu } from '@lobehub/ui/base-ui';
Popoverimport { Popover } from '@lobehub/ui/base-ui';
ScrollAreaimport { ScrollArea } from '@lobehub/ui/base-ui';
Switchimport { Switch } from '@lobehub/ui/base-ui';
Toastimport { Toast } from '@lobehub/ui/base-ui';
FloatingSheetimport { FloatingSheet } from '@lobehub/ui/base-ui';
Drawerimport { Drawer } from '@lobehub/ui/base-ui';

Modal については、専用の modal スキルを参照してください。従来の宣言型パターン <Modal open … /> ではなく、命令型の createModal({ content: … }) パターンを使用してください。base-ui には、すでに SPAGlobalProvider にマウントされた独自の ModalHost があります。

よくある間違い:import { Select } from '@lobehub/ui' は正しそうに見えますが、これは antd ベースの Select です。base-ui の Select を使用してください。Modal、DropdownMenu なども同様です。

@lobehub/ui ルート — base-ui に同等のものがない場合に使用
カテゴリコンポーネント
一般ActionIcon, ActionIconGroup, Block, Button, Icon
データ表示Avatar, Collapse, Empty, Highlighter, Markdown, Tag, Tooltip
データ入力CodeEditor, CopyButton, EditableText, Form, Input, InputPassword, SearchBar, TextArea
レイアウトCenter, DraggablePanel, Flexbox, Grid, Header, MaskShadow
ナビゲーションBurger, Menu, SideNav, Tabs

状態

一時的な状態は、必要な範囲が最小となる所有者に保持してください。状態遷移やハンドラーによってレンダリングが見通しにくくなる場合、または再利用可能な単位となる場合はカスタムフックを抽出してください。コンポーネントが特定の数のフックを持つという理由だけで抽出してはいけません。

実際の状態、再利用、レンダリング更新、またはマウント可能な機能の境界を確立する場合にのみ、コンポーネントを分割してください。ファイルを小さくすることだけを目的に分割してはいけません。ファイルが source-layout の 1200 行制限に達した場合は、行数で区切るのではなく、これらの境界のいずれかを見つけてください。重いドメイン機能をホスト側で組み立てるアトムに分解する作業は、compose-atoms が担当します。

ポップオーバーを離れる場合

ポップオーバーのコンテンツ内にあるアクションによってポップオーバーを離れる場合は、ポップオーバーを閉じる必要があります。閉じないと、遷移先の上にポップオーバーが残ります(たとえば、ユーザーパネルのプランバッジから /settings/plans に移動する場合)。

  • ナビゲーション:コンテンツ内にリンクやナビゲーションを含むホストは、open 状態を保持し、@/hooks/useCloseOnNavigate の useCloseOnNavigate(open, () => setOpen(false)) を呼び出して、返されたキーを Popover に渡します。これにより、後から追加されたリンクや、ほかのファイルから追加されたリンクも対象になります。このキーが重要なのは、ナビゲーションによってホストが <Activity>(ホームサイドバーなど)内で非表示になる場合です。非表示のツリーでは新しいエフェクトが設定されないため、base-ui のポップアップが終了アニメーションを完了できず、再マウントによって削除されるまで画面に残ります。
  • モーダルへの引き継ぎ、または最終選択:モーダルを開く前、または選択後に、NavPanel/switcher/SwitcherMenu.tsx のように usePopoverContext().close()(またはホストのセッター)を呼び出します。ポップオーバーの外部にレンダリングされたコンテンツでは、このコンテキストを使用できません。開発環境では、既定の close が例外をスローするためです。
  • 共有リンクのプライバシー確認のように、結果が同じポップオーバー内に表示される確認ステップでは、ポップオーバーを開いたままにします。

レンダリングパフォーマンスとメモ化

memo、useMemo、useCallback は既定のコンポーネントラッパーではなく、必要に応じて使う最適化として扱います。導入する前に、実際にどこで再レンダリングが起きるかを特定し、まずは構造的な改善を検討してください。

  1. 更新境界で分割します。
  2. 一時的な状態を、最小の所有者に移します。
  3. Zustand のセレクターを絞り込み、広範な購読を避けます。

プロパティを持たないコンポーネントや、単純にレンダリングされるコンポーネント、通常は新しいオブジェクト、配列、関数、JSX の子要素を受け取るコンポーネントはメモ化しないでください。ツリーの上位に保持された状態を補うためにメモ化を使わないでください。

サブツリーが明らかに処理コストの高いもの、または頻繁に繰り返しレンダリングされるものであり、通常の親コンポーネントのレンダリング中に関連する入力が安定していて、プロファイリングまたは具体的なレンダリング経路の分析によって回避できる処理が特定された場合に限り、メモ化を使用してください。その理由を実装の概要または PR に記載してください。

レイアウト

@lobehub/ui の Flexbox と Center を使用してください。すべてのプロパティと例については、references/layout-kit.md を参照してください。

  • Flex の子要素間の間隔には、margin ではなく gap を使用します。
  • 利用可能なスペースを埋めるには、flex={1} を使用します。
  • 複雑なレイアウトでは Flexbox をネストし、スクロール可能な領域には overflow: 'auto' を設定します。

関連スキル

  • ux:読み込み時の表示(シナリオ → references/feedback.md §4.1 のローダーテーブル)と、ユーザー向けのインタラクション設計。
  • modal:命令型の base-ui モーダルパターン。
  • spa-routes:SPA ナビゲーション、ルートの所有権、ルーター設定、.desktop バリアント。
  • compose-atoms:大規模なドメイン機能を、マウント可能な機能アトムに分割します。各ホストは、マウントするものだけをインポートします。
  • zustand:ストアの構造とセレクターの規約。

コメント