npx skills add https://github.com/existential-birds/beagle --skill react-flowReact Flow (@xyflow/react) 是一个用于构建基于节点的图表、工作流编辑器和交互式图表的库。它提供了一个高度可定制的框架,用于创建可视化编程界面、流程图和网络可视化。
pnpm add @xyflow/react
import { ReactFlow, Node, Edge, Background, Controls, MiniMap } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
const initialNodes: Node[] = [
{
id: '1',
type: 'input',
data: { label: 'Input Node' },
position: { x: 250, y: 5 },
},
{
id: '2',
data: { label: 'Default Node' },
position: { x: 100, y: 100 },
},
{
id: '3',
type: 'output',
data: { label: 'Output Node' },
position: { x: 400, y: 100 },
},
];
const initialEdges: Edge[] = [
{ id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e2-3', source: '2', target: '3' },
];
function Flow() {
return (
<div style={{ width: '100vw', height: '100vh' }}>
<ReactFlow nodes={initialNodes} edges={initialEdges}>
<Background />
<Controls />
<MiniMap />
</ReactFlow>
</div>
);
}
export default Flow;
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
节点是图表的基本构建块。每个节点包含:
id: 唯一标识符
type: 节点类型(内置或自定义)
position: { x, y } 坐标
data: 自定义数据对象
import { Node } from '@xyflow/react';
const node: Node = { id: 'node-1', type: 'default', position: { x: 100, y: 100 }, data: { label: 'Node Label' }, style: { background: '#D6D5E6' }, className: 'custom-node', };
内置节点类型:
default: 标准节点input: 无目标连接点output: 无源连接点group: 其他节点的容器边连接节点。每条边需要:
id: 唯一标识符
source: 源节点 ID
target: 目标节点 ID
import { Edge } from '@xyflow/react';
const edge: Edge = { id: 'e1-2', source: '1', target: '2', type: 'smoothstep', animated: true, label: 'Edge Label', style: { stroke: '#fff', strokeWidth: 2 }, };
内置边类型:
default: 贝塞尔曲线straight: 直线step: 带尖角的正交线smoothstep: 带圆角的正交线连接点是节点上的连接点。使用 Position 枚举进行定位:
import { Handle, Position } from '@xyflow/react';
<Handle type="target" position={Position.Top} />
<Handle type="source" position={Position.Bottom} />
可用位置:Position.Top, Position.Right, Position.Bottom, Position.Left
使用状态钩子进行完全控制:
import { useNodesState, useEdgesState, addEdge, OnConnect } from '@xyflow/react';
import { useCallback } from 'react';
function ControlledFlow() {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect: OnConnect = useCallback(
(connection) => setEdges((eds) => addEdge(connection, eds)),
[setEdges]
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
/>
);
}
访问 React Flow 实例以进行程序化控制:
import { useReactFlow } from '@xyflow/react';
function FlowControls() {
const {
getNodes,
getEdges,
setNodes,
setEdges,
addNodes,
addEdges,
deleteElements,
fitView,
zoomIn,
zoomOut,
getNode,
getEdge,
updateNode,
updateEdge,
} = useReactFlow();
return (
<button onClick={() => fitView()}>Fit View</button>
);
}
使用带有类型化数据的 NodeProps<T> 定义自定义节点:
import { NodeProps, Node, Handle, Position } from '@xyflow/react';
export type CustomNode = Node<{ label: string; status: 'active' | 'inactive' }, 'custom'>;
function CustomNodeComponent({ data, selected }: NodeProps<CustomNode>) {
return (
<div className={`px-4 py-2 ${selected ? 'ring-2' : ''}`}>
<Handle type="target" position={Position.Top} />
<div className="font-bold">{data.label}</div>
<Handle type="source" position={Position.Bottom} />
</div>
);
}
使用 nodeTypes 注册:
const nodeTypes: NodeTypes = { custom: CustomNodeComponent };
<ReactFlow nodeTypes={nodeTypes} />
id 属性和 style 进行定位useUpdateNodeInternals([nodeId])className="nodrag" 以防止拖动有关详细模式(包括样式、航空地图标记和动态连接点),请参阅自定义节点参考。
使用 EdgeProps<T> 和路径工具定义自定义边:
import { BaseEdge, EdgeProps, getBezierPath } from '@xyflow/react';
export type CustomEdge = Edge<{ status: 'normal' | 'error' }, 'custom'>;
function CustomEdgeComponent(props: EdgeProps<CustomEdge>) {
const [edgePath] = getBezierPath(props);
return (
<BaseEdge
id={props.id}
path={edgePath}
style={{ stroke: props.data?.status === 'error' ? '#ef4444' : '#64748b' }}
/>
);
}
getBezierPath() - 平滑曲线getStraightPath() - 直线getSmoothStepPath() - 带圆角的正交线getSmoothStepPath({ borderRadius: 0 }) - 带尖角的正交线(阶梯边)所有函数都返回 [path, labelX, labelY, offsetX, offsetY]。
使用 EdgeLabelRenderer 创建支持指针事件的基于 HTML 的标签:
import { EdgeLabelRenderer, BaseEdge, getBezierPath } from '@xyflow/react';
function ButtonEdge(props: EdgeProps) {
const [edgePath, labelX, labelY] = getBezierPath(props);
return (
<>
<BaseEdge id={props.id} path={edgePath} />
<EdgeLabelRenderer>
<div
style={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,
pointerEvents: 'all',
}}
className="nodrag nopan"
>
<button onClick={() => console.log('Delete')}>×</button>
</div>
</EdgeLabelRenderer>
</>
);
}
有关动画边、时间标签和 SVG 文本模式,请参阅自定义边参考。
使用 useReactFlow() 钩子进行程序化视口控制:
import { useReactFlow } from '@xyflow/react';
function ViewportControls() {
const { fitView, zoomIn, zoomOut, setCenter, screenToFlowPosition } = useReactFlow();
// 将所有节点适配到视图中
const handleFitView = () => fitView({ padding: 0.2, duration: 400 });
// 缩放控制
const handleZoomIn = () => zoomIn({ duration: 300 });
const handleZoomOut = () => zoomOut({ duration: 300 });
// 居中到特定坐标
const handleCenter = () => setCenter(250, 250, { zoom: 1.5, duration: 500 });
// 将屏幕坐标转换为流程坐标
const addNodeAtClick = (event: React.MouseEvent) => {
const position = screenToFlowPosition({ x: event.clientX, y: event.clientY });
// 使用 position 添加节点
};
return null;
}
有关保存/恢复状态、受控视口和坐标转换,请参阅视口参考。
React Flow 提供全面的事件处理:
import { NodeMouseHandler, OnNodeDrag } from '@xyflow/react';
const onNodeClick: NodeMouseHandler = (event, node) => {
console.log('Node clicked:', node.id);
};
const onNodeDrag: OnNodeDrag = (event, node, nodes) => {
console.log('Dragging:', node.id);
};
<ReactFlow
onNodeClick={onNodeClick}
onNodeDrag={onNodeDrag}
onNodeDragStop={onNodeClick}
/>
import { EdgeMouseHandler, OnConnect } from '@xyflow/react';
const onEdgeClick: EdgeMouseHandler = (event, edge) => console.log('Edge:', edge.id);
const onConnect: OnConnect = (connection) => console.log('Connected:', connection);
<ReactFlow onEdgeClick={onEdgeClick} onConnect={onConnect} />
import { useOnSelectionChange, useOnViewportChange } from '@xyflow/react';
useOnSelectionChange({
onChange: ({ nodes, edges }) => console.log('Selected:', nodes.length, edges.length),
});
useOnViewportChange({
onChange: (viewport) => console.log('Viewport:', viewport.zoom),
});
有关完整事件目录(包括验证、删除和错误处理),请参阅事件参考。
<input className="nodrag" />
<button className="nodrag nopan">Click me</button>
const isValidConnection = (connection: Connection) => {
return connection.source !== connection.target; // 防止自连接
};
<ReactFlow isValidConnection={isValidConnection} />
const { screenToFlowPosition, setNodes } = useReactFlow();
const onPaneClick = (event: React.MouseEvent) => {
const position = screenToFlowPosition({ x: event.clientX, y: event.clientY });
setNodes(nodes => [...nodes, { id: `node-${Date.now()}`, position, data: { label: 'New' } }]);
};
const { updateNodeData } = useReactFlow();
updateNodeData('node-1', { label: 'Updated' });
updateNodeData('node-1', (node) => ({ ...node.data, count: node.data.count + 1 }));
当在流程外部使用 useReactFlow() 时,用 ReactFlowProvider 包装应用:
import { ReactFlow, ReactFlowProvider, useReactFlow } from '@xyflow/react';
function Controls() {
const { fitView } = useReactFlow(); // 必须在提供者内部
return <button onClick={() => fitView()}>Fit View</button>;
}
function App() {
return (
<ReactFlowProvider>
<Controls />
<ReactFlow nodes={nodes} edges={edges} />
</ReactFlowProvider>
);
}
有关详细的实现模式,请参阅:
每周安装数
427
仓库
GitHub 星标
40
首次出现
2026年1月20日
安全审计
已安装于
opencode362
gemini-cli352
codex346
github-copilot332
cursor291
claude-code287
React Flow (@xyflow/react) is a library for building node-based graphs, workflow editors, and interactive diagrams. It provides a highly customizable framework for creating visual programming interfaces, process flows, and network visualizations.
pnpm add @xyflow/react
import { ReactFlow, Node, Edge, Background, Controls, MiniMap } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
const initialNodes: Node[] = [
{
id: '1',
type: 'input',
data: { label: 'Input Node' },
position: { x: 250, y: 5 },
},
{
id: '2',
data: { label: 'Default Node' },
position: { x: 100, y: 100 },
},
{
id: '3',
type: 'output',
data: { label: 'Output Node' },
position: { x: 400, y: 100 },
},
];
const initialEdges: Edge[] = [
{ id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e2-3', source: '2', target: '3' },
];
function Flow() {
return (
<div style={{ width: '100vw', height: '100vh' }}>
<ReactFlow nodes={initialNodes} edges={initialEdges}>
<Background />
<Controls />
<MiniMap />
</ReactFlow>
</div>
);
}
export default Flow;
Nodes are the building blocks of the graph. Each node has:
id: Unique identifier
type: Node type (built-in or custom)
position: { x, y } coordinates
data: Custom data object
import { Node } from '@xyflow/react';
const node: Node = { id: 'node-1', type: 'default', position: { x: 100, y: 100 }, data: { label: 'Node Label' }, style: { background: '#D6D5E6' }, className: 'custom-node', };
Built-in node types:
default: Standard nodeinput: No target handlesoutput: No source handlesgroup: Container for other nodesEdges connect nodes. Each edge requires:
id: Unique identifier
source: Source node ID
target: Target node ID
import { Edge } from '@xyflow/react';
const edge: Edge = { id: 'e1-2', source: '1', target: '2', type: 'smoothstep', animated: true, label: 'Edge Label', style: { stroke: '#fff', strokeWidth: 2 }, };
Built-in edge types:
default: Bezier curvestraight: Straight linestep: Orthogonal with sharp cornerssmoothstep: Orthogonal with rounded cornersHandles are connection points on nodes. Use Position enum for placement:
import { Handle, Position } from '@xyflow/react';
<Handle type="target" position={Position.Top} />
<Handle type="source" position={Position.Bottom} />
Available positions: Position.Top, Position.Right, Position.Bottom, Position.Left
Use state hooks for full control:
import { useNodesState, useEdgesState, addEdge, OnConnect } from '@xyflow/react';
import { useCallback } from 'react';
function ControlledFlow() {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect: OnConnect = useCallback(
(connection) => setEdges((eds) => addEdge(connection, eds)),
[setEdges]
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
/>
);
}
Access the React Flow instance for programmatic control:
import { useReactFlow } from '@xyflow/react';
function FlowControls() {
const {
getNodes,
getEdges,
setNodes,
setEdges,
addNodes,
addEdges,
deleteElements,
fitView,
zoomIn,
zoomOut,
getNode,
getEdge,
updateNode,
updateEdge,
} = useReactFlow();
return (
<button onClick={() => fitView()}>Fit View</button>
);
}
Define custom nodes using NodeProps<T> with typed data:
import { NodeProps, Node, Handle, Position } from '@xyflow/react';
export type CustomNode = Node<{ label: string; status: 'active' | 'inactive' }, 'custom'>;
function CustomNodeComponent({ data, selected }: NodeProps<CustomNode>) {
return (
<div className={`px-4 py-2 ${selected ? 'ring-2' : ''}`}>
<Handle type="target" position={Position.Top} />
<div className="font-bold">{data.label}</div>
<Handle type="source" position={Position.Bottom} />
</div>
);
}
Register with nodeTypes:
const nodeTypes: NodeTypes = { custom: CustomNodeComponent };
<ReactFlow nodeTypes={nodeTypes} />
id prop and style for positioninguseUpdateNodeInternals([nodeId]) after adding/removing handlesclassName="nodrag" to prevent dragging on inputs/buttonsSee Custom Nodes Reference for detailed patterns including styling, aviation map pins, and dynamic handles.
Define custom edges using EdgeProps<T> and path utilities:
import { BaseEdge, EdgeProps, getBezierPath } from '@xyflow/react';
export type CustomEdge = Edge<{ status: 'normal' | 'error' }, 'custom'>;
function CustomEdgeComponent(props: EdgeProps<CustomEdge>) {
const [edgePath] = getBezierPath(props);
return (
<BaseEdge
id={props.id}
path={edgePath}
style={{ stroke: props.data?.status === 'error' ? '#ef4444' : '#64748b' }}
/>
);
}
getBezierPath() - Smooth curvesgetStraightPath() - Straight linesgetSmoothStepPath() - Orthogonal with rounded cornersgetSmoothStepPath({ borderRadius: 0 }) - Orthogonal with sharp corners (step edge)All return [path, labelX, labelY, offsetX, offsetY].
Use EdgeLabelRenderer for HTML-based labels with pointer events:
import { EdgeLabelRenderer, BaseEdge, getBezierPath } from '@xyflow/react';
function ButtonEdge(props: EdgeProps) {
const [edgePath, labelX, labelY] = getBezierPath(props);
return (
<>
<BaseEdge id={props.id} path={edgePath} />
<EdgeLabelRenderer>
<div
style={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,
pointerEvents: 'all',
}}
className="nodrag nopan"
>
<button onClick={() => console.log('Delete')}>×</button>
</div>
</EdgeLabelRenderer>
</>
);
}
See Custom Edges Reference for animated edges, time labels, and SVG text patterns.
Use useReactFlow() hook for programmatic viewport control:
import { useReactFlow } from '@xyflow/react';
function ViewportControls() {
const { fitView, zoomIn, zoomOut, setCenter, screenToFlowPosition } = useReactFlow();
// Fit all nodes in view
const handleFitView = () => fitView({ padding: 0.2, duration: 400 });
// Zoom controls
const handleZoomIn = () => zoomIn({ duration: 300 });
const handleZoomOut = () => zoomOut({ duration: 300 });
// Center on specific coordinates
const handleCenter = () => setCenter(250, 250, { zoom: 1.5, duration: 500 });
// Convert screen coordinates to flow coordinates
const addNodeAtClick = (event: React.MouseEvent) => {
const position = screenToFlowPosition({ x: event.clientX, y: event.clientY });
// Use position to add node
};
return null;
}
See Viewport Reference for save/restore state, controlled viewport, and coordinate transformations.
React Flow provides comprehensive event handling:
import { NodeMouseHandler, OnNodeDrag } from '@xyflow/react';
const onNodeClick: NodeMouseHandler = (event, node) => {
console.log('Node clicked:', node.id);
};
const onNodeDrag: OnNodeDrag = (event, node, nodes) => {
console.log('Dragging:', node.id);
};
<ReactFlow
onNodeClick={onNodeClick}
onNodeDrag={onNodeDrag}
onNodeDragStop={onNodeClick}
/>
import { EdgeMouseHandler, OnConnect } from '@xyflow/react';
const onEdgeClick: EdgeMouseHandler = (event, edge) => console.log('Edge:', edge.id);
const onConnect: OnConnect = (connection) => console.log('Connected:', connection);
<ReactFlow onEdgeClick={onEdgeClick} onConnect={onConnect} />
import { useOnSelectionChange, useOnViewportChange } from '@xyflow/react';
useOnSelectionChange({
onChange: ({ nodes, edges }) => console.log('Selected:', nodes.length, edges.length),
});
useOnViewportChange({
onChange: (viewport) => console.log('Viewport:', viewport.zoom),
});
See Events Reference for complete event catalog including validation, deletion, and error handling.
<input className="nodrag" />
<button className="nodrag nopan">Click me</button>
const isValidConnection = (connection: Connection) => {
return connection.source !== connection.target; // Prevent self-connections
};
<ReactFlow isValidConnection={isValidConnection} />
const { screenToFlowPosition, setNodes } = useReactFlow();
const onPaneClick = (event: React.MouseEvent) => {
const position = screenToFlowPosition({ x: event.clientX, y: event.clientY });
setNodes(nodes => [...nodes, { id: `node-${Date.now()}`, position, data: { label: 'New' } }]);
};
const { updateNodeData } = useReactFlow();
updateNodeData('node-1', { label: 'Updated' });
updateNodeData('node-1', (node) => ({ ...node.data, count: node.data.count + 1 }));
Wrap the app with ReactFlowProvider when using useReactFlow() outside the flow:
import { ReactFlow, ReactFlowProvider, useReactFlow } from '@xyflow/react';
function Controls() {
const { fitView } = useReactFlow(); // Must be inside provider
return <button onClick={() => fitView()}>Fit View</button>;
}
function App() {
return (
<ReactFlowProvider>
<Controls />
<ReactFlow nodes={nodes} edges={edges} />
</ReactFlowProvider>
);
}
For detailed implementation patterns, see:
Weekly Installs
427
Repository
GitHub Stars
40
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode362
gemini-cli352
codex346
github-copilot332
cursor291
claude-code287
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
106,200 周安装