故障排除
本指南包含在使用 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 或将其记忆化。
当 nodeTypes
或 edgeTypes
属性在初始渲染后发生变化时,会出现此警告。 nodeTypes
或 edgeTypes
仅应在极少数情况下动态更改。 通常,它们只定义一次,其中包含您在应用程序中使用的所有类型。 您很容易在组件渲染函数中定义 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} />;
}
无法创建边。 边需要源和目标。
当您未将 source
和 target
选项传递给边对象时,就会发生这种情况。 如果没有源和目标,边就无法渲染。
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
方法。