学习故障排除

迁移到 React Flow 12

您可以在此处找到旧版 React Flow 的文档:v11v10v9

在您可以使用**React Flow 12 带来的新功能**,例如服务器端渲染、计算流程和暗黑模式之前,您需要首先解决以下重大更改。我们尽量将重大更改降至最低,但其中一些更改是实现新功能所必需的。

迁移指南

在开始迁移之前,您需要安装新的包。

npm install @xyflow/react

1. 新的 npm 包名称

reactflow 已重命名为 @xyflow/react,并且不再是默认导入。您还需要调整样式导入。在 v12 之前,React Flow 分为多个包。现在不再是这种情况。如果您只使用了核心,您现在需要安装 @xyflow/react 包。

旧 API

// npm install reactflow
import ReactFlow from 'reactflow';

新 API

// npm install @xyflow/react
import { ReactFlow } from '@xyflow/react';
 
// you also need to adjust the style import
import '@xyflow/react/dist/style.css';
 
// or if you just want basic styles
import '@xyflow/react/dist/base.css';

2. 节点 measured 属性用于测量的 widthheight

所有测量的节点值现在都存储在 node.measured 中。除了新的包名称之外,这是最大的变化。在 React Flow 测量您的节点后,它会将尺寸写入 node.measured.widthnode.measured.height。如果您正在使用任何布局库,例如 dagre 或 elk,您现在需要从 node.measured 获取尺寸,而不是从 node 获取。如果您正在使用 widthheight,这些值现在将用作内联样式以指定节点尺寸。

旧 API

// getting the measured width and height
const nodeWidth = node.width;
const nodeHeight = node.height;

新 API

// getting the measured width and height
const nodeWidth = node.measured?.width;
const nodeHeight = node.measured?.height;

3. 新的尺寸处理 node.width / node.heightnode.measured.width / node.measured.height

为了支持服务器端渲染,我们不得不稍微调整 API,以便用户可以更容易地传递节点尺寸。为此,我们更改了 node.widthnode.height 属性的行为。在 React Flow 11 中,这些属性是测量值,仅用作参考。在 React Flow 12 中,这些属性用作内联样式以指定节点尺寸。如果您从数据库加载节点,您可能希望从节点中删除 widthheight 属性,因为现在它们的行为略有不同。现在使用 widthheight 意味着尺寸不是基于内容动态的,而是固定的。

旧 API

// in React Flow 11 you might used node.style to set the dimensions
const nodes = [
  {
    id: '1',
    type: 'input',
    data: { label: 'input node' },
    position: { x: 250, y: 5 },
    style: { width: 180, height: 40 },
  },
];

新 API

// in React Flow 12 you can used node.width and node.height to set the dimensions
const nodes = [
  {
    id: '1',
    type: 'input',
    data: { label: 'input node' },
    position: { x: 250, y: 5 },
    width: 180,
    height: 40,
  },
];

如果您想详细了解如何为服务器端渲染配置 React Flow,您可以在 服务器端渲染指南 中阅读相关内容。

4. 更新节点和边

我们不再支持使用对象变异更新节点和边。如果您想更新某个特定属性,您需要创建一个新的节点/边。

旧 API

setNodes((currentNodes) =>
  currentNodes.map((node) => {
    node.hidden = true;
    return node;
  }),
);

新 API

setNodes((currentNodes) =>
  currentNodes.map((node) => ({
    ...node,
    hidden: true,
  })),
);

5. 将 onEdgeUpdate(以及相关 API)重命名为 onReconnect

我们将 onEdgeUpdate 函数重命名为 onReconnect,以及所有相关的 API(如下所示)。新名称更具描述性,并明确表明该函数用于重新连接边。

  • updateEdge 重命名为 reconnectEdge
  • onEdgeUpdateStart 重命名为 onReconnectStart
  • onEdgeUpdate 重命名为 onReconnect
  • onEdgeUpdateEnd 重命名为 onReconnectEnd
  • edgeUpdaterRadius 重命名为 reconnectRadius
  • edge.updatable 重命名为 edge.reconnectable
  • edgesUpdatable 重命名为 edgesReconnectable

旧 API

<ReactFlow
  onEdgeUpdate={onEdgeUpdate}
  onEdgeUpdateStart={onEdgeUpdateStart}
  onEdgeUpdateEnd={onEdgeUpdateEnd}
/>

新 API

<ReactFlow
  onReconnect={onReconnect}
  onReconnectStart={onReconnectStart}
  onReconnectEnd={onReconnectEnd}
/>

6. 将 parentNode 重命名为 parentId

如果您正在使用子流程,您需要将 node.parentNode 重命名为 node.parentIdparentNode 属性有点误导,因为它不是对父节点的引用,而是父节点的 id

旧 API

const nodes = [
  // some nodes ...
  {
    id: 'xyz-id',
    position: { x: 0, y: 0 },
    type: 'default',
    data: {},
    parentNode: 'abc-id',
  },
];

新 API

const nodes = [
  // some nodes ...
  {
    id: 'xyz-id',
    position: { x: 0, y: 0 },
    type: 'default',
    data: {},
    parentId: 'abc-id',
  },
];

7. 自定义节点属性

我们将 xPosyPos 属性重命名为 positionAbsoluteXpositionAbsoluteY

旧 API

function CustomNode({ xPos, yPos }) {
  ...
}

新 API

function CustomNode({ positionAbsoluteX, positionAbsoluteY }) {
  ...
}

8. 处理组件类名

我们重命名了一些用于定义句柄当前状态的类。

  • react-flow__handle-connecting 重命名为 connectingto / connectingfrom
  • react-flow__handle-valid 重命名为 valid

9. getNodesBounds 选项

第二个参数的类型已从 nodeOrigin 更改为 options.nodeOrigin

旧 API

const bounds = getNodesBounds(nodes: Node[], nodeOrigin)

新 API

const bounds = getNodesBounds(nodes: Node[], { nodeOrigin })

10. 用于定义节点和边的 TypeScript 更改

我们简化了类型并修复了关于函数的问题,其中用户可以传递 NodeData 泛型。新的方法是使用所有节点的并集定义自己的节点类型。通过这种更改,您现在可以拥有具有不同数据结构的多个节点类型,并且始终可以通过检查 node.type 属性来区分它们。

新 API

type NumberNode = Node<{ value: number }, 'number'>;
type TextNode = Node<{ text: string }, 'text'>;
type AppNode = NumberNode | TextNode;

然后,您可以像下面这样使用 AppNode 类型

const nodes: AppNode[] = [
  { id: '1', type: 'number', data: { value: 1 }, position: { x: 100, y: 100 } },
  { id: '2', type: 'text', data: { text: 'Hello' }, position: { x: 200, y: 200 } },
];
const onNodesChange: onNodesChange<AppNode> = useCallback((changes) => setNodes(nds => applyChanges(changes, nds)), []);

您可以在 TypeScript 指南 中阅读更多关于此内容的信息。

11. 重命名 nodeInternals

如果您正在使用 nodeInternals,您需要将其重命名为 nodeLookup

旧 API

const node = useStore((s) => s.nodeInternals.get(id));

新 API

const node = useStore((s) => s.nodeLookup.get(id));

12. 删除弃用的函数

我们删除了以下弃用的函数:

  • getTransformForBounds(已替换为 getViewportForBounds
  • getRectOfNodes(已替换为 getNodesBounds
  • project(已替换为 screenToFlowPosition
  • getMarkerEndId
  • updateEdge(已替换为 reconnectEdge

13. 自定义 applyNodeChangesapplyEdgeChanges

如果您自己编写了用于应用更改的函数,则需要处理新的“replace”事件。我们删除了“reset”事件并添加了“replace”事件,该事件替换特定节点或边。

新功能

现在您已成功迁移到 v12,您可以使用所有花哨的功能。如上所述,v12 的最大更新是

1. 服务器端渲染

您可以为节点定义 widthheighthandles。这使得在服务器上渲染流程并在客户端进行水合成为可能:服务器端渲染指南

  • 详细信息:在 v11 中,widthheight 在节点被测量后立即由库设置。这仍然发生,但我们现在使用 measured.widthmeasured.height 来存储这些信息。在以前的版本中,关于 widthheight 始终存在很多困惑。很难理解,您不能使用它来传递实际的宽度或高度。也不清楚这些属性是由库添加的。我们认为新的实现解决了这两个问题:widthheight 是可选属性,可用于定义尺寸,库设置的所有内容都存储在 measured 中。

2. 计算流程

新的钩子 useHandleConnectionsuseNodesData 以及新的 updateNodeupdateNodeData 函数(两者都是 useReactFlow 的一部分)可用于管理节点之间的数据流:计算流程指南。我们还为边添加了这些助手(updateEdgeupdateEdgeData)!

  • 详细信息:处理一个节点数据依赖于另一个节点的流程非常常见。您更新节点 A 并希望在连接的节点 B 中对这些更改做出反应。到目前为止,每个人都必须提出自定义解决方案。在本版本中,我们希望改变这种情况,并为您提供高性能的助手来处理此类用例。

3. 深色模式和 CSS 变量

React Flow 现在附带了一个内置的深色模式,可以通过使用新的 colorMode 属性(“light”、“dark”或“system”)切换:深色模式示例

  • 详细信息:在本版本中,我们希望让在深色模式和浅色模式之间切换变得更容易,并为您提供更好的深色流程起点。如果您传递 colorMode="dark",我们将在包装器中添加类名“dark”并使用它来调整样式。为了使此新功能的实现对我们来说更容易,我们切换到 CSS 变量来实现大多数样式。这些变量也可以在用户端使用来定制流程。

4. 更好的 DX 与 TSDoc

我们开始使用 TSDoc 来获得更好的 DX。在开发过程中,您的 IDE 现在将向您显示属性和钩子的文档。这对我们来说是一个巨大的进步,让库更易于访问和使用。我们也将在不久的将来使用 TSDoc 来生成文档。

更多功能和更新

还有更多!除了新的主要功能外,我们还添加了一些我们列表中长期存在的小功能

  • useConnection 钩子使用此钩子,您可以访问正在进行的连接。例如,您可以使用它对句柄进行着色,根据当前的起始/结束句柄来设置自定义连接线的样式。
  • 受控的 viewport这是一个高级功能。可能的用例是动画视窗或例如为较低分辨率的屏幕四舍五入变换。此功能带来了两个新属性:viewportonViewportChange
  • ViewportPortal 组件:这使得在视窗中渲染元素成为可能,而无需实现自定义节点。
  • onDelete 处理程序:我们添加了一个组合的处理程序 onDeleteNodesonDeleteEdges 以便更容易地对删除做出反应。
  • onBeforeDelete 处理程序:使用此处理程序,您可以阻止/管理删除。
  • isValidConnection 属性:这使得可以为所有连接实现一个验证函数。它也会针对以编程方式添加的边进行调用。
  • autoPanSpeed 属性:用于控制自动平移时的速度。
  • paneClickDistance 属性:鼠标按下/弹起之间触发点击的最大距离。
  • 背景组件:添加 patternClassName 属性以能够使用类名来设置背景图案的样式。如果您想使用 Tailwind 来设置背景图案的样式,这很有用。
  • onMove 回调会针对库调用的视窗更新(如 fitView 或 zoom-in)触发。
  • deleteElements 现在返回删除的节点和删除的边。
  • 添加 origin 属性用于节点。
  • 添加 selectable 属性用于边。
  • 节点调整大小更新:当组大小调整时,子节点不会移动,范围和扩展被正确识别。
  • 更正 BezierEdgeStepEdgeSmoothStepEdgeStraightEdge 组件的类型。
  • 由库创建的新边仅在设置这些属性时具有 sourceHandletargetHandle 属性。(我们以前传递 sourceHandle: nulltargetHandle: null
  • 当边的 z 索引发生变化时,边不会挂载/卸载。
  • 连接线了解目标句柄位置,以便正确绘制路径。
  • nodeDragThreshold 默认情况下为 1,而不是 0。
  • 更好的选择框可用性(在从流程中拖出时捕获)。
  • NodeProps 中添加 selectabledeletabledraggableparentId
  • 在样式未加载时添加警告。

内部更改

这些更改不是面向用户的,但对于那些使用 React Flow 内部存储的人来说可能很重要。

  • 最大的内部更改是我们创建了一个新的包 @xyflow/system,它包含与框架无关的助手,React Flow 和 Svelte Flow 可以使用它们。
    • XYDrag 用于处理节点和选择的拖动。
    • XYPanZoom 用于控制视窗平移和缩放。
    • XYHandle 用于管理新的连接。
  • 我们重命名了 nodeInternalsnodeLookup。该映射用作查找,但我们不会在任何更改时创建新的映射对象,因此它实际上只用作查找。
  • 我们删除了内部“reset”事件并添加了“replace”事件,以便能够更新特定节点。
  • 我们从存储中删除了 connectionNodeIdconnectionHandleIdconnectionHandleType 并添加了 connection.fromHandle.nodeIdconnection.fromHandle.id 等。
  • 在边中添加 data-id
  • onNodeDragStartonNodeDragonNodeDragStop 也会在用户拖动选择时被调用(除了 onSelectionDragStartonSelectionDragonSelectionDragStop)。