删除中间节点
此示例展示了如何在从链中间移除节点时恢复已删除的边。换句话说,如果我们有三个按顺序连接的节点 - 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