mcpField
R
react-flow-code-review

react-flow-code-review

github.com/existential-birdsテスト・品質85319 回インストール11 週間前に更新
リポジトリ

react-flow-code-review について

React Flow を使ったアプリをレビューするスキルです。順序に沿った確認と根拠付きの指摘により、Provider の使い方、コンポーネントの安定性、パフォーマンス、TypeScript の実践を評価します。

主な機能

  1. 01レビュー範囲内の React Flow 利用箇所の特定
  2. 02フックの Provider 境界の確認
  3. 03カスタムノードとエッジの安定性評価
  4. 04描画と状態更新のパフォーマンス確認
  5. 05TypeScript の型と指摘根拠の確認

活用シーン

  1. 01マージ前の React Flow 機能レビュー
  2. 02Provider 外で呼び出されたフックの検出
  3. 03ノードやエッジの不要な再描画の特定
  4. 04React Flow コードの型の問題確認

インストール

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

$npx skills add https://github.com/existential-birds/beagle --skill react-flow-code-review

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

詳細

React Flow のコードレビュー

React Flow のコードをレビューする際は、以下のゲートを順番に完了してください。各ステップには、次へ進む前に満たすべき客観的な合格条件があります。

レビューゲート(順番に実施)

  1. フローコードを特定する — レビュー対象の範囲で ReactFlow、ReactFlowProvider、useReactFlow、@xyflow/react、nodeTypes、edgeTypes を検索します。合格条件: ファイルパスの短い一覧を提示するか、検索後に対象範囲内に「該当なし」と明記します。

  2. プロバイダーの境界 — 各 useReactFlow()(およびプロバイダーを必要とするその他のフック)について、コンポーネントツリーをたどり、囲んでいる ReactFlowProvider があることを確認するか、具体的な不一致を ファイル名:行番号 で記録します。

  3. 型の安定性とメモ化の対象 — カスタムノードまたはエッジの各コンポーネントについて、memo と型付きの props(NodeProps<...> など)を使用しているかを記録します。<ReactFlow> に渡される各 nodeTypes / edgeTypes の値について、安定した参照(モジュールスコープ、または依存配列を示せる useMemo)であることを確認するか、不安定な再生成を ファイル名:行番号 で指摘します。

  4. 根拠を添えて報告する — 報告する各指摘について、ファイルパスと行番号(または最小限の引用スニペット)を記録します。合格条件: 重大または高重大度の問題について、その引用を添えずに記載していません。

  5. チェックリストを完了する — パフォーマンスチェックリスト と よくある間違い を使用し、各項目を 満たしている、(理由を添えて)該当なし、または根拠を添えて 未解決 のいずれかにします。合格条件: 暗黙のまま曖昧になっている項目がありません。

重大なアンチパターン

1. コンポーネント内で nodeTypes/edgeTypes を定義する

問題: レンダリングのたびにすべてのノードが再マウントされます。

// BAD - recreates object every render
function Flow() {
  const nodeTypes = { custom: CustomNode };  // WRONG
  return <ReactFlow nodeTypes={nodeTypes} />;
}

// GOOD - defined outside component
const nodeTypes = { custom: CustomNode };
function Flow() {
  return <ReactFlow nodeTypes={nodeTypes} />;
}

// GOOD - useMemo if dynamic
function Flow() {
  const nodeTypes = useMemo(() => ({ custom: CustomNode }), []);
  return <ReactFlow nodeTypes={nodeTypes} />;
}
2. カスタムノード/エッジに memo() がない

問題: 親コンポーネントが更新されるたびに、カスタムコンポーネントが再レンダリングされます。

// BAD - no memoization
function CustomNode({ data }: NodeProps) {
  return <div>{data.label}</div>;
}

// GOOD - wrapped in memo
import { memo } from 'react';
const CustomNode = memo(function CustomNode({ data }: NodeProps) {
  return <div>{data.label}</div>;
});
3. useCallback を使わないインラインコールバック

問題: 新しい関数参照が作成され、メモ化が機能しなくなります。

// BAD - inline callback
<ReactFlow
  onNodesChange={(changes) => setNodes(applyNodeChanges(changes, nodes))}
/>

// GOOD - memoized callback
const onNodesChange = useCallback(
  (changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
  []
);
<ReactFlow onNodesChange={onNodesChange} />
4. プロバイダーの外部で useReactFlow を使用する
// BAD - will throw error
function App() {
  const { getNodes } = useReactFlow();  // ERROR: No provider
  return <ReactFlow ... />;
}

// GOOD - wrap in provider
function FlowContent() {
  const { getNodes } = useReactFlow();  // Works
  return <ReactFlow ... />;
}

function App() {
  return (
    <ReactFlowProvider>
      <FlowContent />
    </ReactFlowProvider>
  );
}
5. ノードデータに複雑なオブジェクトを格納する

問題: 参照の等価性チェックに失敗し、不要な更新が発生します。

// BAD - new object reference every time
setNodes(nodes.map(n => ({
  ...n,
  data: { ...n.data, config: { nested: 'value' } }  // New object each time
})));

// GOOD - use updateNodeData for targeted updates
const { updateNodeData } = useReactFlow();
updateNodeData(nodeId, { config: { nested: 'value' } });

パフォーマンスチェックリスト

ノードのレンダリング
  • カスタムノードを memo() でラップしている
  • nodeTypes をコンポーネントの外部で定義するか、メモ化している
  • ノード内の負荷の高い計算に useMemo を使用している
  • イベントハンドラーに useCallback を使用している
エッジのレンダリング
  • カスタムエッジを memo() でラップしている
  • edgeTypes をコンポーネントの外部で定義するか、メモ化している
  • エッジのパス計算が重複していない
状態の更新
  • setState の関数形式を使用している:setNodes((nds) => ...)
  • 単一プロパティの更新で状態全体をスプレッドしていない
  • データのみを変更する場合に updateNodeData を使用している
  • 複数のノード/エッジを追加する際に更新をまとめている
ビューポート
  • レンダリングのたびに fitView() を呼び出していない
  • 初回の表示調整にのみ fitViewOptions を使用している
  • アニメーションの時間が適切である(500ms 未満)

よくある間違い

コンテナーの高さが設定されていない
// BAD - no height, flow won't render
<ReactFlow nodes={nodes} edges={edges} />

// GOOD - explicit dimensions
<div style={{ width: '100%', height: '100vh' }}>
  <ReactFlow nodes={nodes} edges={edges} />
</div>
CSS のインポートがない
// Required for default styles
import '@xyflow/react/dist/style.css';
インタラクティブ要素に nodrag を付け忘れている
// BAD - clicking button drags node
<button onClick={handleClick}>Click</button>

// GOOD - prevents drag
<button className="nodrag" onClick={handleClick}>Click</button>
位置定数を使用していない
// BAD - string literals
<Handle type="source" position="right" />

// GOOD - type-safe constants
import { Position } from '@xyflow/react';
<Handle type="source" position={Position.Right} />
ノード/エッジを直接変更している
// BAD - direct mutation
nodes[0].position = { x: 100, y: 100 };
setNodes(nodes);

// GOOD - immutable update
setNodes(nodes.map(n =>
  n.id === '1' ? { ...n, position: { x: 100, y: 100 } } : n
));

TypeScript の問題

ジェネリック型が指定されていない
// BAD - loses type safety
const [nodes, setNodes] = useNodesState(initialNodes);

// GOOD - explicit types
type MyNode = Node<{ value: number }, 'custom'>;
const [nodes, setNodes] = useNodesState<MyNode>(initialNodes);
props の型が間違っている
// BAD - using wrong type
function CustomNode(props: any) { ... }

// GOOD - correct props type
function CustomNode(props: NodeProps<MyNode>) { ... }

レビューの質問

  1. すべてのカスタムコンポーネントがメモ化されていますか?
  2. nodeTypes/edgeTypes はレンダリングの外部で定義されていますか?
  3. コールバックは useCallback でラップされていますか?
  4. コンテナーのサイズは適切ですか?
  5. スタイルはインポートされていますか?
  6. useReactFlow はプロバイダーの内部で使用されていますか?
  7. インタラクティブ要素に nodrag が指定されていますか?
  8. 型は全体を通して一貫して使用されていますか?

コメント