删除中间节点
此示例向你展示了在从链中间移除节点时如何恢复已删除的边。换句话说,如果我们有三个按顺序连接的节点 - a->b->c - 并且我们删除了中间节点 b,此示例向你展示了如何最终得到图 a->c。
🌐 This example shows you how to recover deleted edges when you remove a node from the middle
of a chain. In other words, if we have three nodes connected in sequence - a->b->c - and
we deleted the middle node b, this example shows you how to end up with the graph
a->c.
为了实现这一点,我们需要利用一些位:
🌐 To achieve this, we need to make use of a few bits:
onNodesDelete回调让我们知道何时节点被删除。getConnectedEdges给我们提供与一个节点连接的所有边,无论是作为源节点还是目标节点。getIncomers和getOutgoers给我们提供了作为源或目标与某个节点相连的节点。
总的来说,这使我们能够将与被删除节点连接的所有节点,重新连接到被删除节点所连接的任何节点上。
🌐 All together, this allows us to take all the nodes connected to the deleted node, and reconnect them to any nodes the deleted node was connected to.
import React, { useCallback } from 'react';
import {
ReactFlow,
Background,
useNodesState,
useEdgesState,
addEdge,
getIncomers,
getOutgoers,
getConnectedEdges,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
const initialNodes = [
{
id: '1',
type: 'input',
data: { label: 'Start here...' },
position: { x: -150, y: 0 },
},
{
id: '2',
type: 'input',
data: { label: '...or here!' },
position: { x: 150, y: 0 },
},
{ id: '3', data: { label: 'Delete me.' }, position: { x: 0, y: 100 } },
{ id: '4', data: { label: 'Then me!' }, position: { x: 0, y: 200 } },
{
id: '5',
type: 'output',
data: { label: 'End here!' },
position: { x: 0, y: 300 },
},
];
const initialEdges = [
{ id: '1->3', source: '1', target: '3' },
{ id: '2->3', source: '2', target: '3' },
{ id: '3->4', source: '3', target: '4' },
{ id: '4->5', source: '4', target: '5' },
];
export default function Flow() {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect = useCallback((params) => setEdges(addEdge(params, edges)), [edges]);
const onNodesDelete = useCallback(
(deleted) => {
let remainingNodes = [...nodes];
setEdges(
deleted.reduce((acc, node) => {
const incomers = getIncomers(node, remainingNodes, acc);
const outgoers = getOutgoers(node, remainingNodes, acc);
const connectedEdges = getConnectedEdges([node], acc);
const remainingEdges = acc.filter((edge) => !connectedEdges.includes(edge));
const createdEdges = incomers.flatMap(({ id: source }) =>
outgoers.map(({ id: target }) => ({
id: `${source}->${target}`,
source,
target,
})),
);
remainingNodes = remainingNodes.filter((rn) => rn.id !== node.id);
return [...remainingEdges, ...createdEdges];
}, edges),
);
},
[nodes, edges],
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onNodesDelete={onNodesDelete}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
attributionPosition="top-right"
>
<Background />
</ReactFlow>
);
}虽然这个例子不到20行代码,但内容相当丰富。让我们来分解其中的一些部分:
🌐 Although this example is less than 20 lines of code there’s quite a lot to digest. Let’s break some of it down:
- 我们的
onNodesDelete回调会被调用,并传入一个参数 -deleted- 它是一个包含所有刚被删除节点的数组。如果你选择一个单独的节点并按下删除键,deleted将只包含该节点,但如果你进行选择,选择中的所有节点 都会在deleted中。 - 我们创建一个新的边数组 -
remainingEdges-,其中包含流中与我们刚刚删除的节点无关的所有边。 - 我们通过对
incomers数组进行 flatMapping 来创建另一个边数组。这些是作为源节点与被删除节点连接的节点。对于这些节点中的每一个,我们创建一条新边,连接到outgoers数组中的每个节点。这些是作为目标节点与被删除节点连接的节点。
为了简洁,我们使用了对象解构,同时重命名绑定的变量(例如,({ id: source }) => ...) 解构对象的 id 属性并将其绑定到一个名为 source 的新变量),但你不需要这样做
快速参考
🌐 Quick Reference