学习故障排除

故障排除

本指南包含在使用 React Flow 时可能出现的警告和错误。 我们还添加了从我们的 Discord 服务器Github 问题Github 讨论 收集的常见问题和陷阱。

警告:看起来您没有使用 zustand 提供者作为祖先

这通常发生在

A: 您安装了两个不同版本的 @reactflow/core。
B: 您尝试在 React Flow 上下文之外访问内部 React Flow 状态。

解决方案 A

更新 reactflow 和 @reactflow/node-resizer(如果您正在使用它),删除 node_modules 和 package-lock.json 并重新安装依赖项。

解决方案 B

一个可能的解决方案是用 <ReactFlowProvider /> 包装您的组件,或者将访问状态的代码移动到 React Flow 实例的子级中。

🚫
这将导致错误
import { ReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
 
function FlowWithoutProvider(props) {
  // cannot access the state here
  const reactFlowInstance = useReactFlow();
 
  return <ReactFlow {...props} />;
}
 
export default FlowWithoutProvider;
🚫
这也会导致错误
import { ReactFlow, ReactFlowProvider } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
 
function Flow(props) {
  // still cannot access the state here
  // only child components of this component can access the state
  const reactFlowInstance = useReactFlow();
 
  return (
    <ReactFlowProvider>
      <ReactFlow {...props} />
    </ReactFlowProvider>
  );
}
 
export default FlowWithProvider;
这可以工作

只要您想访问 React Flow 的内部状态(例如通过使用 useReactFlow 钩子),您就需要用 <ReactFlowProvider /> 包装您的组件。 这里包装是在组件外部完成的

import { ReactFlow, ReactFlowProvider } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
 
function Flow(props) {
  // you can access the internal state here
  const reactFlowInstance = useReactFlow();
 
  return <ReactFlow {...props} />;
}
 
// wrapping with ReactFlowProvider is done outside of the component
function FlowWithProvider(props) {
  return (
    <ReactFlowProvider>
      <Flow {...props} />
    </ReactFlowProvider>
  );
}
 
export default FlowWithProvider;

看起来您创建了一个新的 nodeTypes 或 edgeTypes 对象。 如果这不是

有意为之,请在组件外部定义 nodeTypes/edgeTypes 或将其记忆化。

nodeTypesedgeTypes 属性在初始渲染后发生变化时,会出现此警告。 nodeTypesedgeTypes 仅应在极少数情况下动态更改。 通常,它们只定义一次,其中包含您在应用程序中使用的所有类型。 您很容易在组件渲染函数中定义 nodeTypes 或 edgeTypes 对象,这将导致每次组件重新渲染时 React Flow 都重新渲染。

🚫
会导致警告
import { ReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
 
import MyCustomNode from './MyCustomNode';
 
function Flow(props) {
  // new object being created on every render
  // causing unneccessary re-renders
  const nodeTypes = {
    myCustomNode: MyCustomNode,
  };
 
  return <ReactFlow nodeTypes={nodeTypes} />;
}
 
export default Flow;
推荐的实现
import { ReactFlow } from '@xyflow/react';
import MyCustomNode from './MyCustomNode';
 
// defined outside of the component
const nodeTypes = {
  myCustomNode: MyCustomNode,
};
 
function Flow(props) {
  return <ReactFlow nodeTypes={nodeTypes} />;
}
 
export default Flow;
备选实现

如果您想动态更改 nodeTypes 而不导致不必要的重新渲染,可以使用它。

import { useMemo } from 'react';
import { ReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
 
import MyCustomNode from './MyCustomNode';
 
function Flow(props) {
  const nodeTypes = useMemo(
    () => ({
      myCustomNode: MyCustomNode,
    }),
    [],
  );
 
  return <ReactFlow nodeTypes={nodeTypes} />;
}
 
export default Flow;

找不到节点类型。 使用回退类型“default”。

这通常发生在您为其中一个节点指定自定义节点类型,但未将正确的 nodeTypes 属性传递给 React Flow 时。 自定义节点的 type 选项的字符串需要与 nodeTypes 对象的键完全相同。

🚫
无法工作
import { ReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
 
import MyCustomNode from './MyCustomNode';
 
const nodes = [
  {
    id: 'mycustomnode',
    type: 'custom',
    // ...
  },
];
 
function Flow(props) {
  // nodeTypes property is missing, so React Flow cannot find the custom node component to render
  return <ReactFlow nodes={nodes} />;
}
🚫
也不起作用
import { ReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
 
import MyCustomNode from './MyCustomNode';
 
const nodes = [
  {
    id: 'mycustomnode',
    type: 'custom',
    // ...
  },
];
 
const nodeTypes = {
  Custom: MyCustomNode,
};
 
function Flow(props) {
  // node.type and key in nodeTypes object are not exactly the same (capitalized)
  return <ReactFlow nodes={nodes} nodeTypes={nodeTypes} />;
}
这可以工作
import { ReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
 
import MyCustomNode from './MyCustomNode';
 
const nodes = [
  {
    id: 'mycustomnode',
    type: 'custom',
    // ...
  },
];
 
const nodeTypes = {
  custom: MyCustomNode,
};
 
function Flow(props) {
  return <ReactFlow nodes={nodes} nodeTypes={nodeTypes} />;
}

React Flow 父容器需要宽度和高度才能渲染图形。

在幕后,React Flow 会测量父 DOM 元素以调整渲染器。 如果您尝试在没有高度的普通 div 中渲染 React Flow,我们将无法显示图形。 如果您遇到此警告,您需要确保您的包装组件有一些 CSS 附加到它,以便它获得固定高度或继承其父级的 高度。

🚫
这将导致警告
import { ReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
 
function Flow(props) {
  return (
    <div>
      <ReactFlow {...props} />
    </div>
  );
}
工作示例
import { ReactFlow } from '@xyflow/react';
 
function Flow(props) {
  return (
    <div style={{ height: 800 }}>
      <ReactFlow {...props} />
    </div>
  );
}

只有子节点可以使用父级范围。

当您尝试将 extent 选项添加到没有父节点的节点时,会出现此警告。 根据您要执行的操作,您可以删除 extent 选项或指定 parentNode

🚫
显示警告
import { ReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
 
const nodes = [
  {
    id: 'mycustomnode',
    extent: 'parent',
    // ...
  },
];
 
function Flow(props) {
  return <ReactFlow nodes={nodes} />;
}
警告已解决
const nodes = [
  {
    id: 'mycustomnode',
    parentNode: 'someothernode',
    extent: 'parent',
    // ...
  },
];
 
function Flow(props) {
  return <ReactFlow nodes={nodes} />;
}

无法创建边。 边需要源和目标。

当您未将 sourcetarget 选项传递给边对象时,就会发生这种情况。 如果没有源和目标,边就无法渲染。

🚫
将显示警告
import { ReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
 
const nodes = [
  /* ... */
];
 
const edges = [
  {
    nosource: '1',
    notarget: '2',
  },
];
 
function Flow(props) {
  return <ReactFlow nodes={nodes} edges={edges} />;
}
这可以工作
import { ReactFlow } from '@xyflow/react';
 
const nodes = [
  /* ... */
];
 
const edges = [
  {
    source: '1',
    target: '2',
  },
];
 
function Flow(props) {
  return <ReactFlow nodes={nodes} edges={edges} />;
}

id 为“some-id”的旧边不存在。

当您尝试 重新连接边,但您要更新的边已从状态中删除时,就会发生这种情况。 这是一个非常罕见的情况。 请参阅 重新连接边示例 以了解实现细节。

无法为源/目标句柄 id: "some-id" 创建边; 边 id: "some-id"。

如果您正在使用多个句柄,并且句柄无法通过其 id 属性找到,或者您没有通过编程方式 更新节点内部结构(在添加或删除句柄后),就会出现这种情况。请查看 自定义节点示例,了解如何使用多个句柄。

标记类型不存在。

当您尝试指定 React Flow 中未内置的标记类型时,会出现此警告。现有的标记类型已在 此处 文档中介绍。

句柄:未找到节点 ID。

当您尝试在自定义节点组件之外使用 <Handle /> 组件时,会出现此警告。

使用 webpack 4 构建我的应用程序时出现错误。

如果您使用的是 webpack 4,您可能会遇到类似于这样的错误

ERROR in /node_modules/@reactflow/core/dist/esm/index.js 16:19
Module parse failed: Unexpected token (16:19)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.cn/concepts#loaders

React Flow 是一个现代的 JavaScript 代码库,并使用了许多较新的 JavaScript 功能。默认情况下,webpack 4 不会转译您的代码,并且它不知道如何处理 React Flow。

您需要在 webpack 配置文件中添加一些 babel 插件才能使其正常工作

$ npm i --save-dev [email protected] @babel/preset-env @babel/preset-react @babel/plugin-proposal-optional-chaining @babel/plugin-proposal-nullish-coalescing-operator

并像这样配置加载器

{
  test: /node_modules[\/\\]@?reactflow[\/\\].*.js$/,
  use: {
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env', "@babel/preset-react"],
      plugins: [
        "@babel/plugin-proposal-optional-chaining",
        "@babel/plugin-proposal-nullish-coalescing-operator",
      ]
    }
  }
}

如果您使用的是 webpack 5,则无需执行任何操作!React Flow 将开箱即用。

当我的节点包含 <canvas /> 元素时,鼠标事件不能始终如一地工作。

如果您在自定义节点中使用 <canvas /> 元素,您可能会遇到来自画布的鼠标事件中坐标看似不正确的问题。

React Flow 使用 CSS 变换在您放大和缩小时缩放节点。但是,从 DOM 的角度来看,元素的大小仍然相同。如果您有想要计算相对于画布元素的鼠标位置的事件监听器,这可能会导致问题。

为了解决您控制的事件处理程序中的这个问题,您可以将计算出的相对位置按 1 / zoom 的比例进行缩放,其中 zoom 是流的当前缩放级别。要获取当前缩放级别,您可以使用 useReactFlow 钩子的 getZoom 方法。