📦 React Flow Code Review — React Flow代码审查
v1.1.0针对使用 @xyflow/react 的代码,提供反模式、性能缺陷与最佳实践的逐项人工审查清单,帮助在代码评审阶段快速定位常见错误并提升质量。
详细分析 ▾
运行时依赖
版本
- 新增 React Flow 代码审查综合最佳实践指南,聚焦反模式、性能与常见错误。 - 列出关键反模式:不当 memoization、回调使用、Provider 误用等。 - 提供节点/边渲染、状态更新与视口处理的检查清单。 - 解决常见集成错误:缺失容器高度、必需 CSS、事件处理不当。 - 强调 TypeScript 提示,提升自定义节点与组件的类型安全。 - 给出评审问题,确保代码质量与一致性。
安装命令
点击复制技能文档
# React Flow 代码审查 ## 关键反面模式 ### 1. 在组件内部定义 nodeTypes/edgeTypes 问题:会导致每次渲染时所有节点重新挂载。 ``tsx // BAD - recreates object every render function Flow() { const nodeTypes = { custom: CustomNode }; // WRONG return ; } // GOOD - defined outside component const nodeTypes = { custom: CustomNode }; function Flow() { return ; } // GOOD - useMemo if dynamic function Flow() { const nodeTypes = useMemo(() => ({ custom: CustomNode }), []); return ; } ` ### 2. 自定义节点/边缺少 memo() 问题:自定义组件会在父级更新时重复渲染。 `tsx // BAD - no memoization function CustomNode({ data }: NodeProps) { return
{data.label}; } // GOOD - wrapped in memo import { memo } from 'react'; const CustomNode = memo(function CustomNode({ data }: NodeProps) { return {data.label}; }); ` ### 3. 未使用 useCallback 的内联回调 问题:生成新的函数引用,破坏 memoization。 `tsx // BAD - inline callback setNodes(applyNodeChanges(changes, nodes))} /> // GOOD - memoized callback const onNodesChange = useCallback( (changes) => setNodes((nds) => applyNodeChanges(changes, nds)), [] ); ` ### 4. 在 Provider 外使用 useReactFlow `tsx // BAD - will throw error function App() { const { getNodes } = useReactFlow(); // ERROR: No provider return ; } // GOOD - wrap in provider function FlowContent() { const { getNodes } = useReactFlow(); // Works return ; } function App() { return ( ); } ` ### 5. 在节点 data 中存储复杂对象 问题:引用相等性检查失败,导致不必要的更新。 `tsx // 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 在组件外定义或已 memoized - [ ] 节点内部的重计算使用 useMemo - [ ] 事件处理器使用 useCallback ### 边渲染 - [ ] 自定义边已包裹 memo() - [ ] edgeTypes 在组件外定义或已 memoized - [ ] 边路径计算未重复 ### 状态更新 - [ ] 使用 setState 的函数形式:setNodes((nds) => ...) - [ ] 更新单个属性时不展开整个状态 - [ ] 仅修改数据时使用 updateNodeData - [ ] 添加多个节点/边时批量更新 ### 视口 - [ ] 不在每次渲染时调用 fitView() - [ ] 仅在初始化时使用 fitViewOptions - [ ] 动画时长合理(< 500ms) ## 常见错误 ### 缺少容器高度 `tsx // BAD - no height, flow won't render // GOOD - explicit dimensions ` ### 缺少 CSS 引入 `tsx // Required for default styles import '@xyflow/react/dist/style.css'; ` ### 交互元素忘记 nodrag `tsx // BAD - clicking button drags node Click // GOOD - prevents drag Click ` ### 未使用位置常量 `tsx // BAD - string literals // GOOD - type-safe constants import { Position } from '@xyflow/react'; ` ### 直接修改节点/边 `tsx // 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 问题 ### 缺少泛型类型 `tsx // BAD - loses type safety const [nodes, setNodes] = useNodesState(initialNodes); // GOOD - explicit types type MyNode = Node<{ value: number }, 'custom'>; const [nodes, setNodes] = useNodesState(initialNodes); ` ### 错误的 Props 类型 `tsx // BAD - using wrong type function CustomNode(props: any) { ... } // GOOD - correct props type function CustomNode(props: NodeProps) { ... } `` ## 审查问题 1. 所有自定义组件是否都已 memoized? 2. nodeTypes/edgeTypes 是否在渲染外定义? 3. 回调是否包裹在 useCallback 中? 4. 容器尺寸是否正确? 5. 样式是否已引入? 6. useReactFlow 是否在 Provider 内使用? 7. 交互元素是否标记 nodrag? 8. 类型是否在整个项目中一致使用?