关于 react-flow-code-review
react-flow-code-review 是用于审查 React Flow 应用代码的技能,通过按序检查和引用证据,评估 Provider 用法、组件稳定性、性能与 TypeScript 实践。
主要功能
- 01定位审查范围内的 React Flow 用法
- 02检查 Hooks 的 Provider 边界
- 03评估自定义节点和边的稳定性
- 04审查渲染与状态更新性能
- 05核对 TypeScript 类型并提供证据
适用场景
- 01在合并前审查 React Flow 功能
- 02查找在 Provider 外调用的 Hooks
- 03发现节点或边的不必要重渲染
- 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 代码时,请按顺序完成以下检查项。每一步都有明确的通过条件,满足后再继续。
审查检查项(按顺序)
-
定位流程代码 — 在审查范围内搜索
ReactFlow、ReactFlowProvider、useReactFlow、@xyflow/react、nodeTypes和edgeTypes。**通过:**列出简短的文件路径清单(或搜索后明确说明“范围内无相关内容”)。 -
Provider 边界 — 对每个
useReactFlow()(以及其他需要 Provider 的 Hook),沿组件树追溯到外层的ReactFlowProvider,或记录具体的不匹配位置,并注明文件:行号。 -
稳定的类型和 memo 表面 — 对每个自定义节点或边组件,注明是否使用
memo和类型化的 props(NodeProps<...>等)。对于传入<ReactFlow>的每个nodeTypes/edgeTypes值,确认其引用稳定(位于模块作用域,或使用useMemo且能指出其依赖项),否则标记不稳定的重新创建位置,并注明文件:行号。 -
提供证据并报告 — 对要报告的每个发现,记录文件路径和行号(或最小的引用片段)。**通过:**没有任何严重或高严重性问题是在未提供出处的情况下提出的。
-
完成检查清单 — 使用性能检查清单和常见错误;每项都标记为已满足、不适用(并说明原因)或未解决(并提供证据)。**通过:**没有任何项目处于未明确说明的状态。
关键反模式
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>) { ... }
审查问题
- 所有自定义组件都已记忆化吗?
- nodeTypes/edgeTypes 都在渲染函数外部定义吗?
- 回调都使用 useCallback 包装了吗?
- 容器大小设置正确吗?
- 样式已导入吗?
- useReactFlow 是否在 Provider 内部使用?
- 交互元素是否标记了 nodrag?
- 各处是否一致地使用了类型?