疑難排解
本指南包含使用 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
hook),您需要使用 <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 中未內建的標記類型時,會出現此警告。現有的標記類型已記錄於此處。
Handle:找不到節點 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.dev.org.tw/concepts#loaders
React Flow 是一個現代化的 JavaScript 程式碼庫,使用了許多較新的 JavaScript 功能。預設情況下,webpack 4 不會轉換您的程式碼,並且它不知道如何處理 React Flow。
您需要將一些 babel 外掛程式新增至您的 webpack 設定中,才能使其正常運作
$ npm i --save-dev babel-loader@8.2.5 @babel/preset-env @babel/preset-react @babel/plugin-proposal-optional-chaining @babel/plugin-proposal-nullish-coalescing-operator
並像這樣設定 loader
{
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 />
元素,您可能會在 cavnas 中的滑鼠事件中遇到看似不正確的坐標問題。
React Flow 使用 CSS 轉換來縮放節點,當您放大和縮小時。然而,從 DOM 的角度來看,元素的大小仍然相同。如果您有想要計算滑鼠相對於 canvas 元素的位置的事件監聽器,這可能會導致問題。
為了在您控制的事件處理程序中解決此問題,您可以將計算出的相對位置縮放 1 / zoom
,其中 zoom
是 flow 的當前縮放級別。要獲取當前縮放級別,您可以使用 useReactFlow
hook 中的 getZoom
方法。