使用 @xyflow/react正确实现 React Flow 节点式用户界面。适用于构建流程图、图表、可视化编辑器或节点式应用程序...
反弹 Flow 执行 QQQ快速启动是一项面向实际任务的技能,主要用于运行这些门, 顺序为;不要跳过“ 看起来很好 ”;
该技能适合需要稳定复用相关能力的场景,可作为自动化工作流的一部分,也便于后续检查、调整和扩展。从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;
若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。
import { useCallback } from 'react';
import { ReactFlow, useNodesState, useEdgesState, addEdge } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
const initialNodes = [
{ id: '1', position: { x: 0, y: 0 }, data: { label: 'Node 1' } },
{ id: '2', position: { x: 200, y: 100 }, data: { label: 'Node 2' } },
];
const initialEdges = [{ id: 'e1-2', source: '1', target: '2' }];
export default function Flow() {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect = useCallback(
(connection) => setEdges((eds) => addEdge(connection, eds)),
[setEdges]
);
return (
);
}
请按顺序执行以下检查;即使某项“看起来没问题”,也不得跳过。
的代码包必须导入 @xyflow/react/dist/style.css(或等效的 CSS 构建流程),确保节点与边可见,且可交互区域(hit-targets)与视觉呈现一致。useReactFlow 作用域边界 — 通过条件: 所有调用 useReactFlow() 的组件,必须是包裹 的同一棵组件树中 的后代(或你已明确拆分状态管理,并能准确指出两个根节点)。nodeTypes / edgeTypes 稳定性 — 通过条件: 这两个映射对象必须为模块级常量,或通过 useMemo 创建且依赖项稳定;不得在渲染 的组件内部每次渲染都新建一个 { ... } 字面量对象。type)但不同 id 的 Handle,则所有需连接至特定句柄的边,必须显式设置 sourceHandle 或 targetHandle(或你已明确接受默认句柄解析逻辑)。关于 MiniMap、Controls、Background、NodeToolbar 和 NodeResizer 的使用模式,请参阅 ADDITIONAL_COMPONENTS.md。
import type { Node, Edge, NodeProps, BuiltInNode } from '@xyflow/react';
// 定义带数据结构的自定义节点类型
type CustomNode = Node<{ value: number; label: string }, 'custom'>;
// 与内置节点类型合并
type MyNode = CustomNode | BuiltInNode;
type MyEdge = Edge<{ weight?: number }>;
// 在整个应用中统一使用
const [nodes, setNodes] = useNodesState(initialNodes);
import { memo } from 'react';
import { Handle, Position, type NodeProps } from '@xyflow/react';
// 定义节点类型
type CounterNode = Node<{ count: number }, 'counter'>;
// 始终使用 memo 包裹以提升性能
const CounterNode = memo(function CounterNode({ data, isConnectable }: NodeProps) {
return (
<>
Count: {data.count}
{/* nodrag 可防止点击按钮时触发拖拽 */}
>
);
});
// 在 nodeTypes 中注册(务必在组件外部定义,避免重复创建导致重渲染)
const nodeTypes = { counter: CounterNode };
// 在 ReactFlow 中使用
// 当节点存在多个同类型句柄时,应使用 handle ID 区分
// 连接时指定具体句柄
const edge = {
id: 'e1-2',
source: '1',
sourceHandle: 'a',
target: '2',
targetHandle: null
};
import { BaseEdge, EdgeProps, getSmoothStepPath } from '@xyflow/react';
function CustomEdge({ id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data }: EdgeProps) {
const [edgePath, labelX, labelY] = getSmoothStepPath({
sourceX, sourceY, sourcePosition,
targetX, targetY, targetPosition,
});
return (
<>
{data?.label}
>
);
}
const edgeTypes = { custom: CustomEdge };
// 外部状态 + 变更处理器
const [nodes, setNodes] = useState(initialNodes);
const [edges, setEdges] = useState(initialEdges);
const onNodesChange = useCallback(
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
[]
);
const onEdgesChange = useCallback(
(changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
[]
);
useReactFlowimport { useReactFlow, ReactFlowProvider } from '@xyflow/react';
function FlowControls() {
const {
getNodes, setNodes, addNodes, updateNodeData,
getEdges, setEdges, addEdges,
fitView, zoomIn, zoomOut, setViewport,
deleteElements, toObject,
} = useReactFlow();
const addNode = () => {
addNodes({ id: `${Date.now()}`, position: { x: 100, y: 100 }, data: { label: 'New' } });
};
return ;
}
// 使用 useReactFlow 时,必须由 ReactFlowProvider 包裹
function App() {
return (
);
}
const { updateNodeData } = useReactFlow();
// 合并至现有数据
updateNodeData(nodeId, { label: 'Updated' });
// 完全替换数据
updateNodeData(nodeId, { newField: 'value' }, { replace: true });
// 初始渲染时自动适配
// 编程式控制
const { fitView, setViewport, getViewport, zoomTo } = useReactFlow();
// 仅适配指定节点
fitView({ nodes: [{ id: '1' }, { id: '2' }], duration: 500 });
// 设置精确视口
setViewport({ x: 100, y: 100, zoom: 1.5 }, { duration: 300 });
const isValidConnection = useCallback((connection: Connection) => {
// 禁止自连
if (connection.source === connection.target) return false;
// 自定义校验逻辑
const sourceNode = getNode(connection.source);
const targetNode = getNode(connection.target);
return sourceNode?.type !== targetNode?.type;
}, []);
| 类名 | 作用 |
|---|---|
nodrag |
点击该元素时不触发拖拽 |
nowheel |
禁用鼠标滚轮缩放 |
nopan |
禁止从该元素触发平移 |
nokey |
禁用键盘事件(建议用于 input 等表单控件) |
MiniMap、Controls、Background、NodeToolbar 和 NodeResizer 的使用方式详见 ADDITIONAL_COMPONENTS.md。