学習トラブルシューティング

トラブルシューティング

このガイドには、React Flowを使用する際に発生する可能性のある警告とエラーが含まれています。DiscordサーバーGithub IssuesGithub Discussionsから収集したよくある質問や落とし穴も追加しています。

警告: zustand プロバイダーを祖先として使用していないようです

これは通常、次の場合に発生します。

A: @reactflow/core の異なるバージョンが2つインストールされています。
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} />;
}

エッジを作成できません。エッジにはソースとターゲットが必要です。

これは、エッジオブジェクトに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.dokyumento.jp/concepts#loaders

React Flowは最新のJavaScriptコードベースであり、多くの新しいJavaScript機能を使用しています。デフォルトでは、Webpack 4はコードを変換せず、React Flowの処理方法を認識しません。

動作させるには、Webpackの設定にいくつかのBabelプラグインを追加する必要があります。

$ 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

そして、ローダーを次のように設定します。

{
  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 />要素を使用している場合、canvasからのマウスイベントで座標が正しくないように見える問題が発生する可能性があります。

React Flowは、ズームインとズームアウト時にノードをスケーリングするためにCSS変換を使用します。しかし、DOMの観点からは、要素のサイズは同じままです。canvas要素に対するマウス位置を計算しようとするイベントリスナーがある場合、問題が発生する可能性があります。

この問題を解決するには、制御するイベントハンドラーで、計算された相対位置を1 / zoomでスケーリングします。ここでzoomはフローの現在のズームレベルです。getZoomメソッドを使用して現在のズームレベルを取得できます。useReactFlowフックを使用します。