react-flow-architecture
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact Flow Architecture
React Flow 架构设计
When to Use React Flow
何时使用React Flow
Good Fit
适用场景
- Visual programming interfaces
- Workflow builders and automation tools
- Diagram editors (flowcharts, org charts)
- Data pipeline visualization
- Mind mapping tools
- Node-based audio/video editors
- Decision tree builders
- State machine designers
- 可视化编程界面
- 工作流构建器与自动化工具
- 图编辑器(流程图、组织结构图)
- 数据管道可视化
- 思维导图工具
- 基于节点的音视频编辑器
- 决策树构建器
- 状态机设计器
Consider Alternatives
考虑替代方案
- Simple static diagrams (use SVG or canvas directly)
- Heavy real-time collaboration (may need custom sync layer)
- 3D visualizations (use Three.js, react-three-fiber)
- Graph analysis with 10k+ nodes (use WebGL-based solutions like Sigma.js)
- 简单静态图表(直接使用SVG或canvas)
- 重度实时协作场景(可能需要自定义同步层)
- 3D可视化(使用Three.js、react-three-fiber)
- 包含10000+节点的图分析(使用基于WebGL的解决方案如Sigma.js)
Architecture Patterns
架构模式
Package Structure (xyflow)
包结构(xyflow)
@xyflow/system (vanilla TypeScript)
├── Core algorithms (edge paths, bounds, viewport)
├── xypanzoom (d3-based pan/zoom)
├── xydrag, xyhandle, xyminimap, xyresizer
└── Shared types
@xyflow/react (depends on @xyflow/system)
├── React components and hooks
├── Zustand store for state management
└── Framework-specific integrations
@xyflow/svelte (depends on @xyflow/system)
└── Svelte components and storesImplication: Core logic is framework-agnostic. When contributing or debugging, check if issue is in @xyflow/system or framework-specific package.
@xyflow/system (vanilla TypeScript)
├── Core algorithms (edge paths, bounds, viewport)
├── xypanzoom (d3-based pan/zoom)
├── xydrag, xyhandle, xyminimap, xyresizer
└── Shared types
@xyflow/react (depends on @xyflow/system)
├── React components and hooks
├── Zustand store for state management
└── Framework-specific integrations
@xyflow/svelte (depends on @xyflow/system)
└── Svelte components and stores提示:核心逻辑与框架无关。在贡献代码或调试时,需检查问题是出在@xyflow/system还是特定框架的包中。
State Management Approaches
状态管理方案
1. Local State (Simple Apps)
1. 本地状态(简单应用)
tsx
// useNodesState/useEdgesState for prototyping
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);Pros: Simple, minimal boilerplate
Cons: State isolated to component tree
tsx
// useNodesState/useEdgesState for prototyping
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);优点:简单,样板代码少
缺点:状态隔离在组件树中
2. External Store (Production)
2. 外部状态库(生产环境)
tsx
// Zustand store example
import { create } from 'zustand';
interface FlowStore {
nodes: Node[];
edges: Edge[];
setNodes: (nodes: Node[]) => void;
onNodesChange: OnNodesChange;
}
const useFlowStore = create<FlowStore>((set, get) => ({
nodes: initialNodes,
edges: initialEdges,
setNodes: (nodes) => set({ nodes }),
onNodesChange: (changes) => {
set({ nodes: applyNodeChanges(changes, get().nodes) });
},
}));
// In component
function Flow() {
const { nodes, edges, onNodesChange } = useFlowStore();
return <ReactFlow nodes={nodes} onNodesChange={onNodesChange} />;
}Pros: State accessible anywhere, easier persistence/sync
Cons: More setup, need careful selector optimization
tsx
// Zustand store example
import { create } from 'zustand';
interface FlowStore {
nodes: Node[];
edges: Edge[];
setNodes: (nodes: Node[]) => void;
onNodesChange: OnNodesChange;
}
const useFlowStore = create<FlowStore>((set, get) => ({
nodes: initialNodes,
edges: initialEdges,
setNodes: (nodes) => set({ nodes }),
onNodesChange: (changes) => {
set({ nodes: applyNodeChanges(changes, get().nodes) });
},
}));
// In component
function Flow() {
const { nodes, edges, onNodesChange } = useFlowStore();
return <ReactFlow nodes={nodes} onNodesChange={onNodesChange} />;
}优点:状态可在任意位置访问,更易实现持久化/同步
缺点:设置步骤更多,需要谨慎优化选择器
3. Redux/Other State Libraries
3. Redux/其他状态管理库
tsx
// Connect via selectors
const nodes = useSelector(selectNodes);
const dispatch = useDispatch();
const onNodesChange = useCallback((changes: NodeChange[]) => {
dispatch(nodesChanged(changes));
}, [dispatch]);tsx
// Connect via selectors
const nodes = useSelector(selectNodes);
const dispatch = useDispatch();
const onNodesChange = useCallback((changes: NodeChange[]) => {
dispatch(nodesChanged(changes));
}, [dispatch]);Data Flow Architecture
数据流架构
User Input → Change Event → Reducer/Handler → State Update → Re-render
↓
[Drag node] → onNodesChange → applyNodeChanges → setNodes → ReactFlow
↓
[Connect] → onConnect → addEdge → setEdges → ReactFlow
↓
[Delete] → onNodesDelete → deleteElements → setNodes/setEdges → ReactFlow用户输入 → 变更事件 → 归约器/处理器 → 状态更新 → 重新渲染
↓
[拖拽节点] → onNodesChange → applyNodeChanges → setNodes → ReactFlow
↓
[连接节点] → onConnect → addEdge → setEdges → ReactFlow
↓
[删除节点] → onNodesDelete → deleteElements → setNodes/setEdges → ReactFlowSub-Flow Pattern (Nested Nodes)
子流程模式(嵌套节点)
tsx
// Parent node containing child nodes
const nodes = [
{
id: 'group-1',
type: 'group',
position: { x: 0, y: 0 },
style: { width: 300, height: 200 },
},
{
id: 'child-1',
parentId: 'group-1', // Key: parent reference
extent: 'parent', // Key: constrain to parent
position: { x: 10, y: 30 }, // Relative to parent
data: { label: 'Child' },
},
];Considerations:
- Use to constrain dragging
extent: 'parent' - Use to auto-expand parent
expandParent: true - Parent z-index affects child rendering order
tsx
// Parent node containing child nodes
const nodes = [
{
id: 'group-1',
type: 'group',
position: { x: 0, y: 0 },
style: { width: 300, height: 200 },
},
{
id: 'child-1',
parentId: 'group-1', // Key: parent reference
extent: 'parent', // Key: constrain to parent
position: { x: 10, y: 30 }, // Relative to parent
data: { label: 'Child' },
},
];注意事项:
- 使用限制拖拽范围
extent: 'parent' - 使用自动展开父节点
expandParent: true - 父节点的z-index会影响子节点的渲染顺序
Viewport Persistence
视口状态持久化
tsx
// Save viewport state
const { toObject, setViewport } = useReactFlow();
const handleSave = () => {
const flow = toObject();
// flow.nodes, flow.edges, flow.viewport
localStorage.setItem('flow', JSON.stringify(flow));
};
const handleRestore = () => {
const flow = JSON.parse(localStorage.getItem('flow'));
setNodes(flow.nodes);
setEdges(flow.edges);
setViewport(flow.viewport);
};tsx
// Save viewport state
const { toObject, setViewport } = useReactFlow();
const handleSave = () => {
const flow = toObject();
// flow.nodes, flow.edges, flow.viewport
localStorage.setItem('flow', JSON.stringify(flow));
};
const handleRestore = () => {
const flow = JSON.parse(localStorage.getItem('flow'));
setNodes(flow.nodes);
setEdges(flow.edges);
setViewport(flow.viewport);
};Integration Patterns
集成模式
With Backend/API
与后端/API集成
tsx
// Load from API
useEffect(() => {
fetch('/api/flow')
.then(r => r.json())
.then(({ nodes, edges }) => {
setNodes(nodes);
setEdges(edges);
});
}, []);
// Debounced auto-save
const debouncedSave = useMemo(
() => debounce((nodes, edges) => {
fetch('/api/flow', {
method: 'POST',
body: JSON.stringify({ nodes, edges }),
});
}, 1000),
[]
);
useEffect(() => {
debouncedSave(nodes, edges);
}, [nodes, edges]);tsx
// Load from API
useEffect(() => {
fetch('/api/flow')
.then(r => r.json())
.then(({ nodes, edges }) => {
setNodes(nodes);
setEdges(edges);
});
}, []);
// Debounced auto-save
const debouncedSave = useMemo(
() => debounce((nodes, edges) => {
fetch('/api/flow', {
method: 'POST',
body: JSON.stringify({ nodes, edges }),
});
}, 1000),
[]
);
useEffect(() => {
debouncedSave(nodes, edges);
}, [nodes, edges]);With Layout Algorithms
与布局算法集成
tsx
import dagre from 'dagre';
function getLayoutedElements(nodes: Node[], edges: Edge[]) {
const g = new dagre.graphlib.Graph();
g.setGraph({ rankdir: 'TB' });
g.setDefaultEdgeLabel(() => ({}));
nodes.forEach((node) => {
g.setNode(node.id, { width: 150, height: 50 });
});
edges.forEach((edge) => {
g.setEdge(edge.source, edge.target);
});
dagre.layout(g);
return {
nodes: nodes.map((node) => {
const pos = g.node(node.id);
return { ...node, position: { x: pos.x, y: pos.y } };
}),
edges,
};
}tsx
import dagre from 'dagre';
function getLayoutedElements(nodes: Node[], edges: Edge[]) {
const g = new dagre.graphlib.Graph();
g.setGraph({ rankdir: 'TB' });
g.setDefaultEdgeLabel(() => ({}));
nodes.forEach((node) => {
g.setNode(node.id, { width: 150, height: 50 });
});
edges.forEach((edge) => {
g.setEdge(edge.source, edge.target);
});
dagre.layout(g);
return {
nodes: nodes.map((node) => {
const pos = g.node(node.id);
return { ...node, position: { x: pos.x, y: pos.y } };
}),
edges,
};
}Performance Scaling
性能扩展
Node Count Guidelines
节点数量参考策略
| Nodes | Strategy |
|---|---|
| < 100 | Default settings |
| 100-500 | Enable |
| 500-1000 | Simplify custom nodes, reduce DOM elements |
| > 1000 | Consider virtualization, WebGL alternatives |
| 节点数量 | 策略 |
|---|---|
| < 100 | 默认设置 |
| 100-500 | 启用 |
| 500-1000 | 简化自定义节点,减少DOM元素 |
| > 1000 | 考虑虚拟化、WebGL替代方案 |
Optimization Techniques
优化技巧
tsx
<ReactFlow
// Only render nodes/edges in viewport
onlyRenderVisibleElements={true}
// Reduce node border radius (improves intersect calculations)
nodeExtent={[[-1000, -1000], [1000, 1000]]}
// Disable features not needed
elementsSelectable={false}
panOnDrag={false}
zoomOnScroll={false}
/>tsx
<ReactFlow
// Only render nodes/edges in viewport
onlyRenderVisibleElements={true}
// Reduce node border radius (improves intersect calculations)
nodeExtent={[[-1000, -1000], [1000, 1000]]}
// Disable features not needed
elementsSelectable={false}
panOnDrag={false}
zoomOnScroll={false}
/>Trade-offs
权衡选择
Controlled vs Uncontrolled
受控模式 vs 非受控模式
| Controlled | Uncontrolled |
|---|---|
| More boilerplate | Less code |
| Full state control | Internal state |
| Easy persistence | Need |
| Better for complex apps | Good for prototypes |
| 受控模式 | 非受控模式 |
|---|---|
| 样板代码更多 | 代码量更少 |
| 完全控制状态 | 内部管理状态 |
| 易实现持久化 | 需要使用 |
| 适合复杂应用 | 适合原型开发 |
Connection Modes
连接模式
| Strict (default) | Loose |
|---|---|
| Source → Target only | Any handle → any handle |
| Predictable behavior | More flexible |
| Use for data flows | Use for diagrams |
tsx
<ReactFlow connectionMode={ConnectionMode.Loose} />| 严格模式(默认) | 宽松模式 |
|---|---|
| 仅支持源→目标连接 | 任意手柄间均可连接 |
| 行为可预测 | 灵活性更高 |
| 适用于数据流场景 | 适用于图表场景 |
tsx
<ReactFlow connectionMode={ConnectionMode.Loose} />Edge Rendering
边渲染
| Default edges | Custom edges |
|---|---|
| Fast rendering | More control |
| Limited styling | Any SVG/HTML |
| Simple use cases | Complex labels |
| 默认边 | 自定义边 |
|---|---|
| 渲染速度快 | 控制能力更强 |
| 样式选项有限 | 支持任意SVG/HTML |
| 适合简单场景 | 适合复杂标签需求 |