JavaScript

React Flowとは?@xyflow/react(v12)の使い方・インストール・保存を実例で解説

React Flowは、Reactでノード(箱)とエッジ(線)をつなぐ図=ノードベースUIを作るためのライブラリです。フローチャート、ワークフロービルダー、状態遷移図、ノードエディタなどをドラッグ操作つきで実装できます。注意したいのはパッケージ名が変わっている点で、古い記事の react-flow-rendererreactflow は旧名です。現在の正式パッケージは @xyflow/react(2026年7月時点の最新は v12系)で、ノードとエッジを別配列で扱うなどAPIも刷新されました。この記事は最新のv12を前提に、定義・インストール・保存・移行までを実コードで解説します。

まとめ:React Flowの要点

  • React FlowはReact専用のノードベースUIライブラリ。PythonやVue単体では動かない(Svelte版は公式のSvelte Flow、Vueは別プロジェクトのVue Flow)。
  • 正式パッケージは @xyflow/reactreactflow(v11以前)・react-flow-renderer(v10以前)は旧名で、新規採用は非推奨。
  • ライセンスはMIT(無料・商用可)。Proは有料の追加サンプル・サポートで、ライブラリ利用に課金は不要。
  • v12ではノードとエッジを別々の配列で管理し、変更は applyNodeChanges/applyEdgeChanges(または便利フック useNodesState/useEdgesState)で onNodesChange/onEdgesChange に反映する。旧 elementsremoveElements の書き方は廃止。
  • 状態の保存はインスタンスの toObject() でJSON化し、復元は setNodes/setEdges/setViewport で戻す。

React Flowとは:ノードベースUIを作るReactライブラリ

React Flowが扱うのは「ノードとエッジで構成された図」です。四角いノードをドラッグで動かし、ノードのハンドルから線を引いて別ノードにつなぐ——この操作系と描画、ズーム・パン、選択・削除といった土台を丸ごと提供します。自前でSVGやcanvasを組むと数百行かかる部分を、コンポーネントとフックで完結できるのが採用理由です。

代表的な用途は、業務フローやパイプラインを組み立てるワークフロービルダー、ノードをつないで処理を作るノードエディタ(画像処理・LLMのプロンプト連携・ETLなど)、状態遷移図やマインドマップ、組織図といった編集可能なダイアグラムです。逆に「完成済みの図を表示するだけ」なら後述のとおり過剰になります。

パッケージ名の変遷と最新バージョン

React Flowは名称とパッケージが複数回変わっており、これが検索で古い情報にぶつかる主因です。時系列で整理します。

パッケージ名 時期・位置づけ 主なAPI
react-flow-renderer v10以前(旧称) elements配列+removeElements
reactflow v11(旧称) nodes/edges分離・デフォルトimport
@xyflow/react v12(現行・最新) 名前付きimport・measured等

開発元は現在xyflowという名前で、React版のReact FlowとSvelte版のSvelte Flowを公式に維持しています。新規プロジェクトは @xyflow/react を入れれば迷いません。既存の reactflow / react-flow-renderer を使ったコードは、後述の移行章を参照してください。

PythonやVueでの利用可否

結論から言うと、React FlowはReactのコンポーネントとして動く前提で、Python単体やVue単体では動きません。「reactflow python」で調べる人が多いですが、Pythonバックエンド(Django・FastAPIなど)と組み合わせる場合も、画面側はReactでReact Flowを描き、Pythonはノード・エッジのデータをAPIで受け渡す役割になります。Python内でReact Flowを直接レンダリングすることはできません。

他フレームワークで同種のUIが欲しい場合、Svelteなら同じxyflow公式のSvelte Flow、Vueなら別開発のVue Flow(xyflowとは別プロジェクトのコミュニティ実装)という選択肢があります。APIは似ていますが別ライブラリなので、React Flowのコードはそのままは動きません。

React Flowのインストールと最小構成

導入はパッケージのインストールとCSSの読み込みの2点が必須です。CSSを忘れるとノードやエッジが正しく表示されないため、最初に入れておきます。

npm install @xyflow/react

最小のフローは、ノード配列・エッジ配列・3つのハンドラ(ノード変更・エッジ変更・接続)で成り立ちます。v12ではノードとエッジを別配列で持ち、変更は applyNodeChanges / applyEdgeChanges で反映します。<div> に必ず高さを与える点も要注意です(高さ0だと何も見えません)。

import { useState, useCallback } from 'react';
import {
  ReactFlow,
  Background,
  Controls,
  MiniMap,
  addEdge,
  applyNodeChanges,
  applyEdgeChanges,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';

const initialNodes = [
  { id: '1', type: 'input', position: { x: 0, y: 0 }, data: { label: 'Start' } },
  { id: '2', position: { x: 0, y: 120 }, data: { label: 'Step 1' } },
];
const initialEdges = [{ id: 'e1-2', source: '1', target: '2', animated: true }];

export default function FlowChart() {
  const [nodes, setNodes] = useState(initialNodes);
  const [edges, setEdges] = useState(initialEdges);

  const onNodesChange = useCallback(
    (changes) => setNodes((ns) => applyNodeChanges(changes, ns)),
    [],
  );
  const onEdgesChange = useCallback(
    (changes) => setEdges((es) => applyEdgeChanges(changes, es)),
    [],
  );
  const onConnect = useCallback(
    (params) => setEdges((es) => addEdge(params, es)),
    [],
  );

  return (
    <div style={{ width: '100%', height: '500px' }}>
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        onConnect={onConnect}
        fitView
      >
        <Background />
        <Controls />
        <MiniMap />
      </ReactFlow>
    </div>
  );
}

fitView は全ノードが画面に収まるよう初期表示を調整するプロパティです。旧APIの onLoad={(instance) => instance.fitView()} はv12で onInit に変わり、単に全体を映すだけなら fitView プロパティで足ります。ドラッグでのノード移動やエッジ接続は、上記のハンドラを渡した時点で有効になります。

ReactFlowProviderが必要になる場面

<ReactFlow> を1つ置くだけなら ReactFlowProvider は不要です。必要になるのは、React Flowの外側のコンポーネントから内部状態にアクセスするとき——具体的には useReactFlowuseNodes などのフックを、<ReactFlow> の兄弟や親で使う場合です。この場合はツリー全体を ReactFlowProvider で包みます。

import { ReactFlow, ReactFlowProvider, useReactFlow } from '@xyflow/react';

function Toolbar() {
  // Provider がないとこのフックはエラーになる
  const { fitView, zoomIn } = useReactFlow();
  return (
    <div>
      <button onClick={() => zoomIn()}>拡大</button>
      <button onClick={() => fitView()}>全体表示</button>
    </div>
  );
}

export default function App() {
  return (
    <ReactFlowProvider>
      <Toolbar />
      <div style={{ width: '100%', height: '500px' }}>
        <ReactFlow nodes={[]} edges={[]} fitView />
      </div>
    </ReactFlowProvider>
  );
}

ノードとエッジのカスタマイズ

付属の Background(背景グリッド)・Controls(ズーム操作)・MiniMap(全体俯瞰)は、上の最小例のように <ReactFlow> の子として置くだけで動きます。見た目の作り込みはノード側で行うのが基本で、React Flowでは自分のReactコンポーネントをノードとして登録できます。

カスタムノードの作成

カスタムノードは、接続点を表す Handle と、その位置を指定する Position を使って作ります。作ったコンポーネントを nodeTypes に登録し、ノード側の type でその名前を指定すると適用されます。nodeTypes は再レンダリングのたびに作り直さないよう、コンポーネント外か useMemo で固定するのが定石です。

import { memo } from 'react';
import { ReactFlow, Handle, Position } from '@xyflow/react';
import '@xyflow/react/dist/style.css';

const CustomNode = memo(({ data }) => {
  return (
    <div style={{ padding: 10, border: '1px solid #4051b5', borderRadius: 6, background: '#fff' }}>
      <Handle type="target" position={Position.Top} />
      <strong>{data.label}</strong>
      <Handle type="source" position={Position.Bottom} />
    </div>
  );
});

// 再生成を避けるためコンポーネント外で定義する
const nodeTypes = { custom: CustomNode };

const nodes = [
  { id: '1', type: 'custom', position: { x: 0, y: 0 }, data: { label: '独自ノード' } },
];

export default function App() {
  return (
    <div style={{ width: '100%', height: '400px' }}>
      <ReactFlow nodes={nodes} edges={[]} nodeTypes={nodeTypes} fitView />
    </div>
  );
}

旧APIでは position="top" のように文字列で位置を渡していましたが、v12系では Position.Top のenumを使うのが推奨です。カスタムノード内で Handle を置いた位置が、そのままエッジの接続点になります。

フロー状態の保存と復元(JSON化)

「react flow json」で求められているのは、作った図を保存して後で開き直す機能です。React Flowインスタンスの toObject() を呼ぶと、ノード・エッジ・ビューポート(表示位置とズーム)をまとめたオブジェクトが得られます。これをJSONにしてサーバやlocalStorageに保存します。

import { useCallback } from 'react';
import { ReactFlow, ReactFlowProvider, useReactFlow } from '@xyflow/react';

function SaveRestore({ setNodes, setEdges }) {
  const { toObject, setViewport } = useReactFlow();

  const onSave = useCallback(() => {
    const flow = toObject(); // { nodes, edges, viewport }
    localStorage.setItem('flow', JSON.stringify(flow));
  }, [toObject]);

  const onRestore = useCallback(() => {
    const flow = JSON.parse(localStorage.getItem('flow'));
    if (!flow) return;
    setNodes(flow.nodes || []);
    setEdges(flow.edges || []);
    const { x = 0, y = 0, zoom = 1 } = flow.viewport || {};
    setViewport({ x, y, zoom });
  }, [setNodes, setEdges, setViewport]);

  return (
    <div>
      <button onClick={onSave}>保存</button>
      <button onClick={onRestore}>復元</button>
    </div>
  );
}

旧記事のように elements 配列をそのままJSON化する書き方はv12では通りません。ノードとエッジが分離されたため、復元時も setNodessetEdges に分けて戻し、setViewport で表示位置まで再現するのが正しい手順です。サーバ保存にする場合も、保存する中身は同じ toObject() の結果です。

旧バージョン(reactflow / react-flow-renderer)からの移行

ネット上のReact Flow解説の多くは react-flow-renderer 時代のもので、そのまま写経するとv12では動きません。実際に古いコードをv12へ直すとき、つまずきやすい変更点を表にまとめます。

旧(v10以前・v11) 現行 v12(@xyflow/react)
import ReactFlow from ‘reactflow’ import { ReactFlow } from ‘@xyflow/react’
elements 単一配列 nodes と edges の別配列
removeElements / isNode / isEdge applyNodeChanges / applyEdgeChanges
onElementsRemove onNodesChange / onEdgesChange
onLoad onInit
onEdgeUpdate onReconnect
node.parentNode node.parentId
node.width / height(実測値) node.measured.width / height

特に効くのが elements の廃止です。旧APIはノードとエッジを1つの配列に混ぜ、removeElements で消していました。v12はノードとエッジを別配列にし、追加・削除・移動はすべて「変更(changes)」として applyNodeChanges/applyEdgeChanges に流します。import も名前付きに変わり、パッケージも @xyflow/react です。

判断としては、新規なら @xyflow/react 一択です。react-flow-renderer は保守が止まっており、古いReactやAPIに縛られます。既存プロジェクトも、大きな改修のタイミングでv12へ寄せる価値があります。移行は「配列を2つに割り、ハンドラをchanges方式へ書き換える」のが山場で、ノードの見た目やレイアウトのロジックは流用できます。

React Flowが向く場面・避けるべき場面

React Flowは万能ではありません。採用の判断軸は「ユーザーが図を編集するか、こちらが図を見せるだけか」です。

向いているのは、ユーザーが操作する図です。ノードを足す・つなぐ・動かすワークフロービルダー、処理をノードで組むエディタ、ドラッグで並べ替える構成図など、インタラクションが本質のUIでは他の選択肢より圧倒的に速く作れます。ドラッグ中心のUIを自作するなら、react-rndによるドラッグ&リサイズの実装と比べて、接続線やグラフ構造まで面倒を見てくれる点が効きます。

逆に避けたほうがよいのは、静的な図を表示するだけのケースです。編集不要のフローチャートや構成図を出すだけなら、テキストから図を生成するMermaidなどのほうが実装も保守も軽く済みます。編集機能のためだけにReact Flowと状態管理を持ち込むのは過剰です。また前述のとおりReact前提なので、フロントがReactでないプロジェクトや、Pythonバックエンドの管理画面に図だけ埋めたい用途では、フレームワークごと選び直す必要があります。AstroにReactを部分的に組み込む構成のように、必要な画面だけReactにしてReact Flowを載せる折衷も現実的です。

よくある質問

React FlowはPythonで使えますか?

単体では使えません。React FlowはReactコンポーネントとして動くため、画面はReactで実装します。Python(Django・FastAPIなど)はノードやエッジのデータをAPIで受け渡すバックエンドとして組み合わせる形になります。

reactflow と @xyflow/react は何が違いますか?

同じライブラリの新旧パッケージです。reactflow はv11時代の名前、@xyflow/react がv12以降の現行名です。v12ではimportが名前付きになり、ノードとエッジを別配列で扱うなどAPIも変わっています。新規は @xyflow/react を使います。

React Flowは無料ですか?

ライブラリ本体はMITライセンスで無料、商用利用も可能です。有料の「Pro」は高度なサンプルコードや優先サポートを受けられるサブスクリプションで、ライブラリを使うだけなら加入は不要です。

ReactFlowProviderはいつ必要ですか?

<ReactFlow> の外側から useReactFlow などのフックで内部状態を操作するときに必要です。ツールバーや保存ボタンを <ReactFlow> の外に置く構成では、全体を ReactFlowProvider で包みます。単体で表示するだけなら不要です。

VueでReact Flowは動きますか?

React FlowはVueでは動きません。Vueで同種のノードUIを作るには、別プロジェクトのVue Flowを使います。API設計は似ていますが別ライブラリなので、React Flowのコードはそのまま移植できません。Svelteの場合はxyflow公式のSvelte Flowがあります。

右クリックメニュー(コンテキストメニュー)は付けられますか?

付けられます。<ReactFlow>onNodeContextMenu(ノード上で右クリック)や onPaneContextMenu(背景で右クリック)でイベントを受け取り、自前のメニューUIを表示します。React Flow自体は既製のメニュー部品を持たないため、位置計算と表示は自分で実装します。

関連記事

資料請求

RELATED POSTS 関連記事