react-flow
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact Flow
React Flow
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.
React Flow (@xyflow/react) 是一个用于构建基于节点的图形、工作流编辑器和交互式图表的库。它提供了高度可定制的框架,用于创建可视化编程界面、流程流和网络可视化。
Quick Start
快速开始
Installation
安装
bash
pnpm add @xyflow/reactbash
pnpm add @xyflow/reactBasic Setup
基础配置
typescript
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;typescript
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;Core Concepts
核心概念
Nodes
节点
Nodes are the building blocks of the graph. Each node has:
- : Unique identifier
id - : Node type (built-in or custom)
type - : { x, y } coordinates
position - : Custom data object
data
typescript
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:
- : Standard node
default - : No target handles
input - : No source handles
output - : Container for other nodes
group
节点是图形的构建块。每个节点包含:
- : 唯一标识符
id - : 节点类型(内置或自定义)
type - : { x, y } 坐标
position - : 自定义数据对象
data
typescript
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 - : 无目标Handle
input - : 无源Handle
output - : 其他节点的容器
group
Edges
边
Edges connect nodes. Each edge requires:
- : Unique identifier
id - : Source node ID
source - : Target node ID
target
typescript
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:
- : Bezier curve
default - : Straight line
straight - : Orthogonal with sharp corners
step - : Orthogonal with rounded corners
smoothstep
边用于连接节点。每条边需要:
- : 唯一标识符
id - : 源节点ID
source - : 目标节点ID
target
typescript
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
Handles
Handle(连接点)
Handles are connection points on nodes. Use enum for placement:
Positiontypescript
import { Handle, Position } from '@xyflow/react';
<Handle type="target" position={Position.Top} />
<Handle type="source" position={Position.Bottom} />Available positions: , , ,
Position.TopPosition.RightPosition.BottomPosition.LeftHandle是节点上的连接点。使用枚举来设置位置:
Positiontypescript
import { Handle, Position } from '@xyflow/react';
<Handle type="target" position={Position.Top} />
<Handle type="source" position={Position.Bottom} />可用位置:、、、
Position.TopPosition.RightPosition.BottomPosition.LeftState Management
状态管理
Controlled Flow
受控流
Use state hooks for full control:
typescript
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}
/>
);
}使用状态钩子实现完全控制:
typescript
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}
/>
);
}useReactFlow Hook
useReactFlow 钩子
Access the React Flow instance for programmatic control:
typescript
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>
);
}访问React Flow实例以进行程序化控制:
typescript
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>
);
}Custom Nodes
自定义节点
Define custom nodes using with typed data:
NodeProps<T>typescript
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 :
nodeTypestypescript
const nodeTypes: NodeTypes = { custom: CustomNodeComponent };
<ReactFlow nodeTypes={nodeTypes} />使用带类型数据的定义自定义节点:
NodeProps<T>typescript
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>
);
}通过注册:
nodeTypestypescript
const nodeTypes: NodeTypes = { custom: CustomNodeComponent };
<ReactFlow nodeTypes={nodeTypes} />Key Patterns
关键模式
- Multiple Handles: Use prop and
idfor positioningstyle - Dynamic Handles: Call after adding/removing handles
useUpdateNodeInternals([nodeId]) - Interactive Elements: Add to prevent dragging on inputs/buttons
className="nodrag"
See Custom Nodes Reference for detailed patterns including styling, aviation map pins, and dynamic handles.
- 多个Handle: 使用属性和
id进行定位style - 动态Handle: 添加/删除Handle后调用
useUpdateNodeInternals([nodeId]) - 交互元素: 添加以防止输入框/按钮被拖拽
className="nodrag"
有关详细模式(包括样式、航空地图标记和动态Handle),请参阅自定义节点参考。
Custom Edges
自定义边
Define custom edges using and path utilities:
EdgeProps<T>typescript
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' }}
/>
);
}使用和路径工具定义自定义边:
EdgeProps<T>typescript
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' }}
/>
);
}Path Utilities
路径工具
- - Smooth curves
getBezierPath() - - Straight lines
getStraightPath() - - Orthogonal with rounded corners
getSmoothStepPath() - - Orthogonal with sharp corners (step edge)
getSmoothStepPath({ borderRadius: 0 })
All return .
[path, labelX, labelY, offsetX, offsetY]- - 平滑曲线
getBezierPath() - - 直线
getStraightPath() - - 带圆角的正交线
getSmoothStepPath() - - 带锐角的正交线(step边)
getSmoothStepPath({ borderRadius: 0 })
所有方法均返回。
[path, labelX, labelY, offsetX, offsetY]Interactive Labels
交互式标签
Use for HTML-based labels with pointer events:
EdgeLabelRenderertypescript
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.
使用创建支持指针事件的基于HTML的标签:
EdgeLabelRenderertypescript
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文本模式,请参阅自定义边参考。
Viewport Control
视口控制
Use hook for programmatic viewport control:
useReactFlow()typescript
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.
使用钩子进行程序化视口控制:
useReactFlow()typescript
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 });
// 使用该位置添加节点
};
return null;
}有关保存/恢复状态、受控视口和坐标转换,请参阅视口参考。
Events
事件
React Flow provides comprehensive event handling:
React Flow提供全面的事件处理:
Node Events
节点事件
typescript
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}
/>typescript
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}
/>Edge and Connection Events
边和连接事件
typescript
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} />typescript
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} />Selection and Viewport Events
选择和视口事件
typescript
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.
typescript
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),
});有关完整的事件目录(包括验证、删除和错误处理),请参阅事件参考。
Common Patterns
常见模式
Preventing Drag/Pan
阻止拖拽/平移
typescript
<input className="nodrag" />
<button className="nodrag nopan">Click me</button>typescript
<input className="nodrag" />
<button className="nodrag nopan">Click me</button>Connection Validation
连接验证
typescript
const isValidConnection = (connection: Connection) => {
return connection.source !== connection.target; // Prevent self-connections
};
<ReactFlow isValidConnection={isValidConnection} />typescript
const isValidConnection = (connection: Connection) => {
return connection.source !== connection.target; // 防止自连接
};
<ReactFlow isValidConnection={isValidConnection} />Adding Nodes on Click
点击添加节点
typescript
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' } }]);
};typescript
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' } }]);
};Updating Node Data
更新节点数据
typescript
const { updateNodeData } = useReactFlow();
updateNodeData('node-1', { label: 'Updated' });
updateNodeData('node-1', (node) => ({ ...node.data, count: node.data.count + 1 }));typescript
const { updateNodeData } = useReactFlow();
updateNodeData('node-1', { label: 'Updated' });
updateNodeData('node-1', (node) => ({ ...node.data, count: node.data.count + 1 }));Provider Pattern
Provider模式
Wrap the app with when using outside the flow:
ReactFlowProvideruseReactFlow()typescript
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>
);
}当在流外部使用时,用包裹应用:
useReactFlow()ReactFlowProvidertypescript
import { ReactFlow, ReactFlowProvider, useReactFlow } from '@xyflow/react';
function Controls() {
const { fitView } = useReactFlow(); // 必须在Provider内部
return <button onClick={() => fitView()}>Fit View</button>;
}
function App() {
return (
<ReactFlowProvider>
<Controls />
<ReactFlow nodes={nodes} edges={edges} />
</ReactFlowProvider>
);
}Reference Files
参考文档
For detailed implementation patterns, see:
- Custom Nodes - NodeProps typing, Handle component, dynamic handles, styling patterns
- Custom Edges - EdgeProps typing, path utilities, EdgeLabelRenderer, animated edges
- Viewport - useReactFlow methods, fitView options, coordinate conversion
- Events - Node/edge/connection events, selection handling, viewport changes
有关详细的实现模式,请参阅:
- 自定义节点 - NodeProps类型定义、Handle组件、动态Handle、样式模式
- 自定义边 - EdgeProps类型定义、路径工具、EdgeLabelRenderer、动画边
- 视口 - useReactFlow方法、fitView选项、坐标转换
- 事件 - 节点/边/连接事件、选择处理、视口变化