mcpField
R
react-flow-code-review

react-flow-code-review

github.com/existential-birds测试与质量85319 次安装11 周前更新
代码仓库

关于 react-flow-code-review

react-flow-code-review 是用于审查 React Flow 应用代码的技能,通过按序检查和引用证据,评估 Provider 用法、组件稳定性、性能与 TypeScript 实践。

主要功能

  1. 01定位审查范围内的 React Flow 用法
  2. 02检查 Hooks 的 Provider 边界
  3. 03评估自定义节点和边的稳定性
  4. 04审查渲染与状态更新性能
  5. 05核对 TypeScript 类型并提供证据

适用场景

  1. 01在合并前审查 React Flow 功能
  2. 02查找在 Provider 外调用的 Hooks
  3. 03发现节点或边的不必要重渲染
  4. 04检查 React 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. Provider 边界 — 对每个 useReactFlow()(以及其他需要 Provider 的 Hook),沿组件树追溯到外层的 ReactFlowProvider,或记录具体的不匹配位置,并注明文件:行号。

  3. 稳定的类型和 memo 表面 — 对每个自定义节点或边组件,注明是否使用 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. 在 Provider 外部使用 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 是否在 Provider 内部使用?
  7. 交互元素是否标记了 nodrag?
  8. 各处是否一致地使用了类型?

评论

支持 Markdown