React Flowとは?図やフローチャートを簡単作成できるライブラリ徹底解説
React Flowは、Reactアプリケーション上でインタラクティブなフローチャート、ダイアグラム、ワークフローなどを視覚的に構築できる強力なライブラリです。豊富な機能とカスタマイズ性により、シンプルなフローチャートから複雑なビジネスプロセスまで、様々なユースケースに対応できます。本記事では、React Flowの基本的な概念から高度な応用まで、徹底的に解説します。
目次
- React Flowとは?
- 1.1. React Flowの概要
- 1.2. React Flowのメリット・デメリット
- 1.3. React Flowの主要な機能
- React Flowの基本
- 2.1. インストールと初期設定
- 2.2. 基本的なノードとエッジの作成
- 2.3. ノードとエッジのスタイリング
- 2.4. レイアウトのカスタマイズ
- 2.5. イベントハンドリング
- React Flowの高度な機能
- 3.1. カスタムノードの実装
- 3.2. カスタムエッジの実装
- 3.3. ドラッグ&ドロップ機能
- 3.4. マウス操作(ズーム、パン)
- 3.5. Context Menuの実装
- 3.6. ミニマップの活用
- 3.7. バックグラウンドグリッドのカスタマイズ
- 3.8. プログラムによるノードとエッジの操作
- 3.9. データのシリアライズとデシリアライズ
- 3.10. React Contextとの連携
- React Flowの応用事例
- 4.1. シンプルなフローチャートの作成
- 4.2. ワークフローエディタの作成
- 4.3. 組織図の作成
- 4.4. ER図の作成
- 4.5. インタラクティブなマップの作成
- React Flowのパフォーマンス最適化
- 5.1. 不要な再レンダリングの防止
- 5.2. 大規模なグラフの処理
- React Flowの関連ライブラリとツール
- 6.1. React Flow Renderer
- 6.2. D3.jsとの連携
- 6.3. X6との比較
- React Flowのトラブルシューティング
- 7.1. よくあるエラーとその解決策
- 7.2. デバッグのヒント
- まとめと今後の展望
1. React Flowとは?
1.1. React Flowの概要
React Flowは、Reactアプリケーション上にインタラクティブなフローチャートやダイアグラムを作成するためのオープンソースのReactライブラリです。ノードとエッジと呼ばれる要素を組み合わせて、様々な図形を表現できます。
- ノード: 図形の基本的な構成要素。長方形、円、多角形など、様々な形状を表現できます。
- エッジ: ノード間の接続線。ノード間の関係性を示します。
React Flowは、直感的で使いやすいAPIを提供しており、React開発者は簡単にフローチャートやダイアグラムをアプリケーションに組み込むことができます。また、豊富なカスタマイズオプションが用意されており、アプリケーションの要件に合わせて外観や動作を自由に調整できます。
1.2. React Flowのメリット・デメリット
メリット:
- 直感的なAPI: シンプルでわかりやすいAPIにより、簡単にフローチャートやダイアグラムを作成できます。
- 高いカスタマイズ性: ノード、エッジ、レイアウトなど、様々な要素を自由にカスタマイズできます。
- インタラクティブ性: ドラッグ&ドロップ、ズーム、パンなど、豊富なインタラクション機能を備えています。
- Reactとの親和性: Reactコンポーネントとして動作するため、既存のReactアプリケーションに容易に統合できます。
- 豊富なコミュニティとドキュメント: 活発なコミュニティと充実したドキュメントにより、開発をスムーズに進めることができます。
- オープンソース: 無償で利用でき、自由に拡張や修正が可能です。
デメリット:
- 学習コスト: ある程度のReactの知識が必要となります。
- 複雑な要件への対応: 高度なカスタマイズを行う場合、それなりの開発工数が必要になる場合があります。
- パフォーマンス: 大規模なグラフを扱う場合、パフォーマンスの問題が発生する可能性があります(後述のパフォーマンス最適化で対策できます)。
1.3. React Flowの主要な機能
- ノードとエッジの作成・編集: ノードとエッジをプログラムまたはUI操作で作成、編集、削除できます。
- ドラッグ&ドロップ: ノードをドラッグ&ドロップで移動できます。
- ズームとパン: マウスホイールやタッチ操作でズームイン・アウト、ドラッグでパンできます。
- ノードのスタイル設定: ノードの色、形状、サイズなどを自由に設定できます。
- エッジのスタイル設定: エッジの色、太さ、種類(直線、曲線、破線など)を設定できます。
- レイアウトアルゴリズム: 自動レイアウトアルゴリズムを利用して、ノードの配置を自動化できます。
- カスタムノード: 独自のUIを持つノードを作成できます。
- カスタムエッジ: 独自の描画ロジックを持つエッジを作成できます。
- イベントハンドリング: ノードやエッジのクリック、ドラッグなどのイベントを処理できます。
- データのシリアライズ/デシリアライズ: グラフの状態をJSON形式で保存したり、ロードしたりできます。
- ミニマップ: グラフ全体の概要を表示するミニマップを表示できます。
- バックグラウンドグリッド: グラフの背景にグリッドを表示できます。
- Context Menu: ノードやエッジを右クリックした際に表示されるコンテキストメニューを実装できます。
2. React Flowの基本
2.1. インストールと初期設定
まず、React Flowをプロジェクトにインストールします。npmまたはyarnを使用できます。
“`bash
npm install react-flow-renderer @react-flow/core @react-flow/background @react-flow/controls
または
yarn add react-flow-renderer @react-flow/core @react-flow/background @react-flow/controls
“`
次に、React Flowを使用するための基本的なコンポーネントをインポートします。
“`javascript
import ReactFlow, {
ReactFlowProvider,
Controls,
Background,
useNodesState,
useEdgesState,
} from ‘react-flow-renderer’;
import ‘@react-flow/core/dist/style.css’;
import ‘@react-flow/background/dist/style.css’;
import ‘@react-flow/controls/dist/style.css’;
const MyFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
return (
);
};
export default MyFlow;
“`
ReactFlowProvider
: React Flowを使用するために必要なコンテキストプロバイダです。React Flowコンポーネントをラップする必要があります。ReactFlow
: メインのReact Flowコンポーネントです。ノードとエッジを表示し、インタラクションを処理します。Controls
: ズームとパンのためのコントロールを表示します。Background
: 背景にグリッドまたはドットを表示します。useNodesState
,useEdgesState
: ノードとエッジの状態を管理するためのReact Hookです。
2.2. 基本的なノードとエッジの作成
ノードとエッジは、JavaScriptオブジェクトとして定義されます。
“`javascript
const initialNodes = [
{ id: ‘1’, position: { x: 100, y: 100 }, data: { label: ‘Node 1’ } },
{ id: ‘2’, position: { x: 300, y: 100 }, data: { label: ‘Node 2’ } },
];
const initialEdges = [
{ id: ‘e1-2’, source: ‘1’, target: ‘2’, animated: true },
];
“`
id
: ノードまたはエッジの一意な識別子です。position
: ノードの位置です。x
とy
の座標を指定します。data
: ノードに関連付けるデータです。label
はノードに表示されるテキストを指定します。source
: エッジの始点となるノードのIDです。target
: エッジの終点となるノードのIDです。animated
: エッジをアニメーション表示するかどうかを指定します。
これらのノードとエッジをReactFlow
コンポーネントに渡すことで、グラフが表示されます。
“`javascript
import ReactFlow, {
ReactFlowProvider,
Controls,
Background,
useNodesState,
useEdgesState,
} from ‘react-flow-renderer’;
import ‘@react-flow/core/dist/style.css’;
import ‘@react-flow/background/dist/style.css’;
import ‘@react-flow/controls/dist/style.css’;
const initialNodes = [
{ id: ‘1’, position: { x: 100, y: 100 }, data: { label: ‘Node 1’ } },
{ id: ‘2’, position: { x: 300, y: 100 }, data: { label: ‘Node 2’ } },
];
const initialEdges = [
{ id: ‘e1-2’, source: ‘1’, target: ‘2’, animated: true },
];
const MyFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
return (
);
};
export default MyFlow;
“`
2.3. ノードとエッジのスタイリング
ノードとエッジのスタイルは、CSSまたはJavaScriptで設定できます。
CSS:
react-flow__node
クラスとreact-flow__edge
クラスを使用して、ノードとエッジの基本的なスタイルを設定できます。
“`css
.react-flow__node {
background-color: #fff;
border: 1px solid #ccc;
padding: 10px;
}
.react-flow__edge {
stroke: #ccc;
stroke-width: 2px;
}
“`
JavaScript:
ノードとエッジのstyle
プロパティを使用して、個々の要素のスタイルを設定できます。
“`javascript
const initialNodes = [
{
id: ‘1’,
position: { x: 100, y: 100 },
data: { label: ‘Node 1’ },
style: { backgroundColor: ‘lightblue’ },
},
];
const initialEdges = [
{
id: ‘e1-2’,
source: ‘1’,
target: ‘2’,
animated: true,
style: { stroke: ‘red’, strokeWidth: 3 },
},
];
“`
2.4. レイアウトのカスタマイズ
React Flowは、いくつかのレイアウトアルゴリズムをサポートしています。fitView
プロパティをtrueに設定すると、グラフ全体がビューポートに収まるように自動的にズームとパンが行われます。
また、react-flow-renderer
は、dagre
やelkjs
などの外部ライブラリと連携することで、より複雑なレイアウトアルゴリズムを適用できます。
bash
npm install dagre @dagrejs/react-dagre
“`javascript
import dagre from ‘dagre’;
import { useMemo, useState, useCallback } from ‘react’;
import ReactFlow, { ReactFlowProvider, addEdge, useNodesState, useEdgesState, Controls, Background } from ‘react-flow-renderer’;
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));
const nodeWidth = 172;
const nodeHeight = 36;
const getLayoutedElements = (nodes, edges, direction = ‘TB’) => {
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));
const isHorizontal = direction === ‘LR’;
dagreGraph.setGraph({ rankdir: direction });
nodes.forEach((node) => {
dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
});
edges.forEach((edge) => {
dagreGraph.setEdge(edge.source, edge.target);
});
dagre.layout(dagreGraph);
nodes.forEach((node) => {
const nodeWithPosition = dagreGraph.node(node.id);
node.targetPosition = isHorizontal ? ‘left’ : ‘top’;
node.sourcePosition = isHorizontal ? ‘right’ : ‘bottom’;
// We are shifting the dagre node position (中心) to top left
node.position = {
x: nodeWithPosition.x - nodeWidth / 2,
y: nodeWithPosition.y - nodeHeight / 2,
};
return node;
});
return { nodes, edges };
};
const initialNodes = [
{ id: ‘1’, data: { label: ‘Node 1’ } },
{ id: ‘2’, data: { label: ‘Node 2’ } },
{ id: ‘3’, data: { label: ‘Node 3’ } },
{ id: ‘4’, data: { label: ‘Node 4’ } },
{ id: ‘5’, data: { label: ‘Node 5’ } },
{ id: ‘6’, data: { label: ‘Node 6’ } },
];
const initialEdges = [
{ id: ‘e1-2’, source: ‘1’, target: ‘2’ },
{ id: ‘e1-3’, source: ‘1’, target: ‘3’ },
{ id: ‘e2-4’, source: ‘2’, target: ‘4’ },
{ id: ‘e3-5’, source: ‘3’, target: ‘5’ },
{ id: ‘e3-6’, source: ‘3’, target: ‘6’ },
];
const LayoutFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const [direction, setDirection] = useState(‘TB’);
const { nodes: layoutedNodes, edges: layoutedEdges } = useMemo(() => getLayoutedElements(nodes, edges, direction), [nodes, edges, direction]);
return (
);
};
export default LayoutFlow;
“`
2.5. イベントハンドリング
React Flowは、ノードやエッジに対する様々なイベントを処理できます。
onNodesChange
: ノードが変更されたときに呼び出される関数です。onEdgesChange
: エッジが変更されたときに呼び出される関数です。onNodeClick
: ノードがクリックされたときに呼び出される関数です。onEdgeClick
: エッジがクリックされたときに呼び出される関数です。onConnect
: ノード間が接続されたときに呼び出される関数です。onNodeDrag
: ノードがドラッグされたときに呼び出される関数です。
“`javascript
import ReactFlow, {
ReactFlowProvider,
Controls,
Background,
useNodesState,
useEdgesState,
addEdge,
} from ‘react-flow-renderer’;
import ‘@react-flow/core/dist/style.css’;
import ‘@react-flow/background/dist/style.css’;
import ‘@react-flow/controls/dist/style.css’;
const initialNodes = [
{ id: ‘1’, position: { x: 100, y: 100 }, data: { label: ‘Node 1’ } },
{ id: ‘2’, position: { x: 300, y: 100 }, data: { label: ‘Node 2’ } },
];
const initialEdges = [];
const MyFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect = (params) => setEdges((eds) => addEdge(params, eds));
const onNodeClick = (event, node) => {
alert(Node ${node.id} clicked
);
};
return (
);
};
export default MyFlow;
“`
3. React Flowの高度な機能
3.1. カスタムノードの実装
React Flowでは、独自のUIを持つカスタムノードを作成できます。nodeTypes
プロパティを使用して、ノードの種類と対応するReactコンポーネントを登録します。
“`javascript
import ReactFlow, {
ReactFlowProvider,
Controls,
Background,
useNodesState,
useEdgesState,
} from ‘react-flow-renderer’;
import ‘@react-flow/core/dist/style.css’;
import ‘@react-flow/background/dist/style.css’;
import ‘@react-flow/controls/dist/style.css’;
const CustomNode = ({ data }) => {
return (
);
};
const nodeTypes = {
custom: CustomNode,
};
const initialNodes = [
{ id: ‘1’, type: ‘custom’, position: { x: 100, y: 100 }, data: { label: ‘Custom Node’ } },
];
const initialEdges = [];
const MyFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
return (
);
};
export default MyFlow;
“`
CustomNode
コンポーネントは、data
プロパティを受け取ります。このdata
プロパティには、ノードのdata
フィールドに設定された値が格納されます。上記の例では、data.label
を使用してノードにテキストを表示しています。
3.2. カスタムエッジの実装
カスタムノードと同様に、独自の描画ロジックを持つカスタムエッジを作成できます。edgeTypes
プロパティを使用して、エッジの種類と対応するReactコンポーネントを登録します。
カスタムエッジの作成はやや複雑ですが、React Flowのドキュメントに詳しい説明があります。
3.3. ドラッグ&ドロップ機能
React Flowは、標準でノードのドラッグ&ドロップをサポートしています。draggable
プロパティをfalseに設定すると、ノードのドラッグを無効にできます。
また、useReactFlow
フックを使用すると、React Flowの状態やAPIにアクセスできます。これを利用して、外部の要素をReact Flowにドラッグ&ドロップする機能などを実装できます。
3.4. マウス操作(ズーム、パン)
React Flowは、マウスホイールによるズームとドラッグによるパンを標準でサポートしています。zoomOnScroll
プロパティとpanOnDrag
プロパティをfalseに設定すると、それぞれの機能を無効にできます。
3.5. Context Menuの実装
ノードやエッジを右クリックした際に表示されるコンテキストメニューを実装できます。onNodeContextMenu
やonEdgeContextMenu
イベントを使用して、右クリックされた要素の情報を取得し、コンテキストメニューを表示する処理を実装します。
3.6. ミニマップの活用
MiniMap
コンポーネントを使用すると、グラフ全体の概要を表示するミニマップを表示できます。ミニマップは、大規模なグラフを操作する際に、現在表示されている範囲を把握するのに役立ちます。
3.7. バックグラウンドグリッドのカスタマイズ
Background
コンポーネントを使用すると、グラフの背景にグリッドまたはドットを表示できます。variant
プロパティでグリッドまたはドットを選択し、gap
プロパティとsize
プロパティで間隔とサイズを調整できます。
3.8. プログラムによるノードとエッジの操作
useReactFlow
フックを使用すると、React Flowの状態やAPIにアクセスできます。これを利用して、プログラムからノードとエッジを追加、更新、削除したり、グラフのズームやパンを制御したりできます。
3.9. データのシリアライズとデシリアライズ
getElements
関数とsetElements
関数を使用すると、グラフの状態をJSON形式で保存したり、ロードしたりできます。これにより、グラフの状態をローカルストレージやデータベースに保存し、後で復元できます。
3.10. React Contextとの連携
React Flowは、React Contextと連携できます。React Flowの状態やAPIをContext Providerでラップすることで、子コンポーネントからReact Flowの状態にアクセスしたり、APIを呼び出したりできます。
4. React Flowの応用事例
4.1. シンプルなフローチャートの作成
最も基本的な応用例として、シンプルなフローチャートを作成できます。ノードを配置し、エッジで接続することで、処理の流れを視覚的に表現できます。
4.2. ワークフローエディタの作成
ワークフローエディタを作成できます。カスタムノードを使用して、ワークフローの各ステップを表現し、エッジでステップ間の関係を定義できます。ドラッグ&ドロップや接続操作を実装することで、ユーザーがGUI上でワークフローを編集できるようなインターフェースを提供できます。
4.3. 組織図の作成
組織図を作成できます。ノードを組織の各メンバーに対応させ、エッジで上下関係を表現します。レイアウトアルゴリズムを適用することで、自動的に見やすい組織図を生成できます。
4.4. ER図の作成
ER図(Entity Relationship Diagram)を作成できます。ノードをエンティティに対応させ、エッジでエンティティ間の関係を表現します。カスタムノードを使用して、エンティティの属性を表示できます。
4.5. インタラクティブなマップの作成
カスタムノードとカスタムエッジを組み合わせることで、インタラクティブなマップを作成できます。ノードを地図上の地点に対応させ、エッジで地点間の経路を表現します。ノードをクリックすると、関連情報を表示するなどのインタラクションを実装できます。
5. React Flowのパフォーマンス最適化
5.1. 不要な再レンダリングの防止
React Flowは、状態が変更されるたびに再レンダリングされます。ノードやエッジが多い場合、再レンダリングのコストが大きくなる可能性があります。React.memo
やuseMemo
などのReactの最適化テクニックを使用して、不要な再レンダリングを防止することが重要です。
5.2. 大規模なグラフの処理
大規模なグラフを扱う場合、初期ロード時間やインタラクションのパフォーマンスが低下する可能性があります。以下の対策を検討してください。
- 仮想化: 表示範囲外のノードやエッジをレンダリングしないことで、初期ロード時間を短縮できます。
- チャンク分割: 大量のデータを一度にロードするのではなく、必要な部分だけをロードすることで、初期ロード時間を短縮できます。
- Web Worker: グラフの計算処理をWeb Workerにオフロードすることで、メインスレッドの負荷を軽減し、インタラクションのパフォーマンスを向上させることができます。
6. React Flowの関連ライブラリとツール
6.1. React Flow Renderer
react-flow-renderer
は、React Flowのコアライブラリです。ノードとエッジの表示、インタラクションの処理など、基本的な機能を提供します。
6.2. D3.jsとの連携
D3.jsは、データ可視化のための強力なJavaScriptライブラリです。React FlowとD3.jsを連携させることで、より複雑なグラフやダイアグラムを作成できます。D3.jsで計算されたレイアウトをReact Flowに適用したり、D3.jsで描画されたカスタムノードをReact Flowに組み込んだりできます。
6.3. X6との比較
X6は、AntVが提供するグラフエディタエンジンです。React Flowと同様に、グラフベースのアプリケーションを構築するために使用できます。X6は、豊富な機能と高度なカスタマイズ性を提供しますが、React Flowよりも学習コストが高い傾向があります。
どちらのライブラリを選択するかは、プロジェクトの要件や開発者のスキルセットによって異なります。シンプルなフローチャートやダイアグラムを作成する場合は、React Flowが適しているでしょう。より複雑なグラフエディタを構築する場合は、X6を検討する価値があります。
7. React Flowのトラブルシューティング
7.1. よくあるエラーとその解決策
- ノードやエッジが表示されない: ノードやエッジの
id
が重複していないか、position
が正しいかを確認してください。 - イベントが発火しない: イベントハンドラーが正しく設定されているか、ノードやエッジがイベントをブロックしていないかを確認してください。
- パフォーマンスが低い: 不要な再レンダリングが発生していないか、大規模なグラフを効率的に処理できているかを確認してください。
7.2. デバッグのヒント
- React DevTools: React DevToolsを使用して、コンポーネントのpropsやstateを確認できます。
- Console.log:
console.log
を使用して、ノードやエッジのデータを表示したり、イベントハンドラーが呼び出されているかを確認したりできます。 - React Flowのデバッグモード: React Flowには、デバッグモードが用意されています。デバッグモードを有効にすると、グラフの状態やイベントのログが表示されます。
8. まとめと今後の展望
React Flowは、Reactアプリケーション上でインタラクティブなフローチャートやダイアグラムを作成するための強力なライブラリです。豊富な機能とカスタマイズ性により、様々なユースケースに対応できます。
今後、React Flowは、さらなる機能拡張やパフォーマンス改善が進められることが期待されます。例えば、
- より高度なレイアウトアルゴリズムのサポート
- WebGLによるレンダリングの高速化
- コラボレーション機能の強化
React Flowは、今後もグラフベースのアプリケーション開発において、重要な役割を担うでしょう。
この記事が、React Flowを理解し、活用するための一助となれば幸いです。