360 Secure SkillHub
360 安全技能中心

React Flow Code Review

核心功能:按步骤审查React Flow代码,涵盖Provider边界检查、稳定类型与memo校验、性能优化、常见错误排查、TypeScript规范落实,问题均附文件路径和行号证据。典型场景:@xyflow/react代码审查、排查节点式UI错误、优化React Flow性能。输入为React Flow相关代码,输出含问题详情及整改建议的审查报告,明确检查结果状态。

anderskev
anderskev
热度 57.03
最近更新 2026-05-11 17:37:23
分类:开发依赖:纯提示词应用场景:代码审查 / 调试排错

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add react-flow-code-review
Metadata
name
react-flow-code-review
description
Reviews React Flow code for anti-patterns, performance issues, and best practices. Use when reviewing code that uses @xyflow/react, checking for common mistakes, or optimizing node-based UI implementations.

React Flow Code Review

When reviewing React Flow code, complete the gates below in order. Each step has an objective pass condition before moving on.

Review gates (sequenced)

  1. Locate flow code — Search the review scope for ReactFlow, ReactFlowProvider, useReactFlow, @xyflow/react, nodeTypes, and edgeTypes. Pass: a short list of file paths (or explicit “none in scope” after searching).

  2. Provider boundary — For each useReactFlow() (and other hooks that require the provider), trace the component tree to an enclosing ReactFlowProvider, or record a concrete mismatch with file:line.

  3. Stable types and memo surfaces — For each custom node or edge component, note whether it uses memo and typed props (NodeProps<...>, etc.). For each nodeTypes / edgeTypes value passed into <ReactFlow>, confirm a stable reference (module scope, or useMemo with deps you can point to) or flag unstable recreation with file:line.

  4. Report with evidence — For each finding you will deliver, record file path and line number(s) (or a minimal quoted snippet). Pass: no critical or high-severity issue is stated without that citation.

  5. Close the checklists — Use Performance Checklist and Common Mistakes; each item is satisfied, not applicable (with reason), or open with evidence. Pass: no item left silently ambiguous.

Critical Anti-Patterns

1. Defining nodeTypes/edgeTypes Inside Components

Problem: Causes all nodes to re-mount on every render.

// 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. Missing memo() on Custom Nodes/Edges

Problem: Custom components re-render on every parent update.

// 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. Inline Callbacks Without useCallback

Problem: Creates new function references, breaking memoization.

// 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. Using useReactFlow Outside Provider

// 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. Storing Complex Objects in Node Data

Problem: Reference equality checks fail, causing unnecessary updates.

// 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' } });

Performance Checklist

Node Rendering

  • Custom nodes wrapped in memo()
  • nodeTypes defined outside component or memoized
  • Heavy computations inside nodes use useMemo
  • Event handlers use useCallback

Edge Rendering

  • Custom edges wrapped in memo()
  • edgeTypes defined outside component or memoized
  • Edge path calculations are not duplicated

State Updates

  • Using functional form of setState: setNodes((nds) => ...)
  • Not spreading entire state for single property updates
  • Using updateNodeData for data-only changes
  • Batch updates when adding multiple nodes/edges

Viewport

  • Not calling fitView() on every render
  • Using fitViewOptions for initial fit only
  • Animation durations are reasonable (< 500ms)

Common Mistakes

Missing Container Height

// 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>

Missing CSS Import

// Required for default styles
import '@xyflow/react/dist/style.css';

Forgetting nodrag on Interactive Elements

// BAD - clicking button drags node
<button onClick={handleClick}>Click</button>

// GOOD - prevents drag
<button className="nodrag" onClick={handleClick}>Click</button>

Not Using Position Constants

// BAD - string literals
<Handle type="source" position="right" />

// GOOD - type-safe constants
import { Position } from '@xyflow/react';
<Handle type="source" position={Position.Right} />

Mutating Nodes/Edges Directly

// 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 Issues

Missing Generic Types

// BAD - loses type safety
const [nodes, setNodes] = useNodesState(initialNodes);

// GOOD - explicit types
type MyNode = Node<{ value: number }, 'custom'>;
const [nodes, setNodes] = useNodesState<MyNode>(initialNodes);

Wrong Props Type

// BAD - using wrong type
function CustomNode(props: any) { ... }

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

Review Questions

  1. Are all custom components memoized?
  2. Are nodeTypes/edgeTypes defined outside render?
  3. Are callbacks wrapped in useCallback?
  4. Is the container sized properly?
  5. Are styles imported?
  6. Is useReactFlow used inside a provider?
  7. Are interactive elements marked with nodrag?
  8. Are types used consistently throughout?