删除中间节点
此示例展示了如何在从链中间移除节点时恢复已删除的边。换句话说,如果我们有三个按顺序连接的节点 - 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回调让我们知道何时删除节点。¥The
onNodesDeletecallback lets us know when a node is deleted. -
getConnectedEdges为我们提供连接到节点的所有边缘,无论是作为源还是目标。¥
getConnectedEdgesgives us all the edges connected to a node, either as source or target. -
getIncomers和getOutgoers为我们提供连接到节点作为源或目标的节点。¥
getIncomersandgetOutgoersgive us the nodes connected to a node as source or target.
总之,这使我们能够获取连接到已删除节点的所有节点,并将它们重新连接到已删除节点所连接的任何节点。
¥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中。¥Our
onNodesDeletecallback is called with one argument -deleted- that is an array of every node that was just deleted. If you select an individual node and press the delete key,deletedwill contain just that node, but if you make a selection all the nodes in that selection will be indeleted. -
我们创建一个新的边数组 -
remainingEdges- 包含与我们刚刚删除的节点无关的流中的所有边缘。¥We create a new array of edges -
remainingEdges- that contains all the edges in the flow that have nothing to do with the node(s) we just deleted. -
我们通过 flatMapping 覆盖
incomers数组来创建另一个边数组。这些是作为源连接到已删除节点的节点。对于这些节点中的每一个,我们创建一个连接到outgoers数组中每个节点的新边。这些是作为目标连接到已删除节点的节点。¥We create another array of edges by flatMapping over the array of
incomers. These are nodes that were connected to the deleted node as a source. For each of these nodes, we create a new edge that connects to each node in the array ofoutgoers. These are nodes that were connected to the deleted node as a target.
为简洁起见,我们使用对象解构,同时重命名变量绑定(例如,({ id: source }) => ...) 解构对象的 id 属性并将其绑定到名为 source 的新变量),但你不需要这样做
¥For brevity, we’re using object destructuring while at the same time renaming
the variable bound (e.g. ({ id: source }) => ...) destructures the id
property of the object and binds it to a new variable called source) but you
don’t need to do this
快速参考
¥Quick Reference