v10への移行

旧バージョンのReact Flowのドキュメントはこちらにあります:v11v10v9

React Flow v10へようこそ!メジャーバージョンアップデートに伴い、多くの新機能が追加されましたが、いくつかの破壊的変更もあります。

新機能

  • サブフロー:親ノードにノードを追加し、グループやネストされたフローを作成できるようになりました。
  • ノードタイプ「group」:ハンドルを持たない新しいノードタイプで、グループノードとして使用できます。
  • タッチデバイスサポート:タッチデバイスでノードを接続できるようになりました。
  • 初期化時のビューのフィット:新しい fitView プロップを使用して、初期ビューにフィットさせることができます。
  • キー操作:単一キーだけでなく、複数のキーやキーの組み合わせも可能になりました。
  • useKeyPressフック:キーボードイベントを処理するためのユーティリティフックです。
  • useReactFlowフック:フローを操作する関数を公開するReact Flowインスタンスを返します。
  • useNodesuseEdgesuseViewportフック:ノード、エッジ、ビューポートを受け取るためのフックです。
  • エッジマーカー:エッジの開始および終了マーカーを構成するためのより多くのオプション。

破壊的変更

要約

  • elements配列をnodes配列とedges配列に分割し、onNodesChangeonEdgesChangeハンドラーを実装します(詳細はコアコンセプトセクションを参照)。
  • カスタム nodeTypesedgeTypes をメモ化してください。
  • onLoadonInit に名前変更
  • paneMoveablepanOnDrag に名前変更
  • useZoomPanHelperuseReactFlow に名前変更(および setTransformsetViewport に)
  • ノードとエッジのオプション isHiddenhidden に名前変更

破壊的変更の詳細な説明

1. 要素 - ノードとエッジ

多くの人が半制御された elements プロップで苦労しているのを見てきました。ローカルのユーザー状態とReact Flowの内部状態を同期させるのは常に少し面倒でした。ドキュメント化されていなかった内部ストアを使用していた人もおり、常にハッキーな解決策でした。新バージョンでは、React Flowを使用する2つの方法を提供します - 非制御と制御です。

1.1. 制御された nodesedges

完全な制御を行い、ローカルの状態またはストアからノードとエッジを使用する場合は、onNodesChangeonEdgesChangeハンドラーと組み合わせてnodesedgesプロップを使用できます。インタラクティブなフローにはこれらのハンドラーを実装する必要があります(パンとズームだけで良い場合は必要ありません)。ノードが初期化、ドラッグ、選択、または削除されるときに変更を受け取ります。つまり、ノードの正確な位置と寸法、または選択されているかどうかを常に知ることができます。変更を適用するために使用するヘルパー関数 applyNodeChangesapplyEdgeChanges をエクスポートします。

旧API

import { useState, useCallback } from 'react';
import { ReactFlow, removeElements, addEdge } from 'react-flow-renderer';
 
const initialElements = [
  { id: '1', data: { label: 'Node 1' }, position: { x: 250, y: 0 } },
  { id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
  { id: 'e1-2', source: '1', target: '2' },
];
 
const BasicFlow = () => {
  const [elements, setElements] = useState(initialElements);
  const onElementsRemove = useCallback(
    (elementsToRemove) =>
      setElements((els) => removeElements(elementsToRemove, els)),
    [],
  );
  const onConnect = useCallback((connection) =>
    setElements((es) => addEdge(connection, es)),
  );
 
  return (
    <ReactFlow
      elements={elements}
      onElementsRemove={onElementsRemove}
      onConnect={onConnect}
    />
  );
};
 
export default BasicFlow;

新API

import { useState, useCallback } from 'react';
import {
  ReactFlow,
  applyNodeChanges,
  applyEdgeChanges,
  addEdge,
} from 'react-flow-renderer';
 
const initialNodes = [
  { id: '1', data: { label: 'Node 1' }, position: { x: 250, y: 0 } },
  { id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
];
 
const initialEdges = [{ id: 'e1-2', source: '1', target: '2' }];
 
const BasicFlow = () => {
  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((connection) =>
    setEdges((eds) => addEdge(connection, eds)),
  );
 
  return (
    <ReactFlow
      nodes={nodes}
      edges={edges}
      onNodesChange={onNodesChange}
      onEdgesChange={onEdgesChange}
      onConnect={onConnect}
    />
  );
};
 
export default BasicFlow;

クイックスタートには、新しいフック useNodesStateuseEdgesState も使用できます。

const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);

関連する変更

  • onElementsClick ->onNodeClickonEdgeClick
  • onElementsRemove -> onNodesChangeonEdgesChange ハンドラーで置き換えられました。

1.2 非制御された defaultNodesdefaultEdges

最も簡単に始める方法は、defaultNodes プロパティと defaultEdges プロパティを使用することです。これらのプロパティを設定すると、すべてのアクションが内部的に処理されます。ノードのドラッグ、ノードの接続、ノードとエッジの削除を可能にする、完全にインタラクティブなフローを得るために、他のハンドラーを追加する必要はありません。

新しいAPI

import ReactFlow from 'react-flow-renderer';
 
const defaultNodes = [
  { id: '1', data: { label: 'Node 1' }, position: { x: 250, y: 0 } },
  { id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
];
 
const defaultEdges = [{ id: 'e1-2', source: '1', target: '2' }];
 
const BasicFlow = () => {
  return <ReactFlow defaultNodes={defaultNodes} defaultEdges={defaultEdges} />;
};
 
export default BasicFlow;

ノードまたはエッジを追加、削除、または更新する場合は、新しいuseReactFlowフックを使用するか、インスタンスを関数パラメーターとして取得するonInitハンドラーを使用することで取得できるReactFlowインスタンス を使用してのみ実行できます。

2. カスタムnodeTypesedgeTypesのメモ化

新しいノードタイプまたはエッジタイプを渡すたびに、バックグラウンドでラップされたノードまたはエッジコンポーネントタイプが作成されます。つまり、毎回レンダリングするたびに新しいnodeTypeまたはedgeTypeオブジェクトを作成しないでください。**nodeTypesとedgeTypesをメモ化するか、変更されない場合はコンポーネントの外で定義してください。**

このようにしないでください

これにより、毎回のレンダリングで新しいオブジェクトが作成され、バグとパフォーマンスの問題につながります。

// this is bad! Don't do it.
<ReactFlow
  nodes={[]}
  nodeTypes={{
    specialType: SpecialNode, // bad!
  }}
/>

このようにしてください

function Flow() {
  const nodeTypes = useMemo(() => ({ specialType: SpecialNode }), []);
 
  return <ReactFlow nodes={[]} nodeTypes={nodeTypes} />;
}

または、変更されない場合はコンポーネントの外でタイプを作成します。

const nodeTypes = { specialType: SpecialNode };
 
function Flow() {
  return <ReactFlow nodes={[]} nodeTypes={nodeTypes} />;
}

3. Redux - Zustand

状態管理ライブラリをReduxからZustandに変更しました。この変更により、状態関連のコードから約300LOCを削除することができました。内部ストアにアクセスする必要がある場合は、useStoreフックを使用できます。

古いAPI

import { useStoreState, useStoreActions } from 'react-flow-renderer';
 
...
 
const transform = useStoreState((store) => store.transform);

新しいAPI

import { useStore } from 'react-flow-renderer';
 
...
const transform = useStore((store) => store.transform);

内部ストアにアクセスする場合は、コンポーネントを<ReactFlowProvider />でラップする必要があります。

再レンダリングをトリガーせずに、たとえばイベントハンドラーでストアを取得する必要がある場合に備えて、useStoreApiもエクスポートしています。

import { useStoreApi } from 'react-flow-renderer';
 
...
 
const store = useStoreApi();
 
...
// in an event handler
const [x, y, zoom] = store.getState().transform;

4. onLoad - onInit

onLoadコールバックはonInitに名前が変更され、ノードが初期化されたときに実行されるようになりました。

古いAPI

const onLoad = (reactFlowInstance: OnLoadParams) => reactFlowInstance.zoomTo(2);
...
<ReactFlow
   ...
  onLoad={onLoad}
/>

新しいAPI

const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.zoomTo(2);
...
<ReactFlow
   ...
  onInit={onInit}
/>

5. paneMoveable - panOnDrag

これはAPIの他の部分(panOnScrollzoomOnScrollなど)とより整合性があります。

古いAPI

<ReactFlow
   ...
  paneMoveable={false}
/>

新しいAPI

<ReactFlow
   ...
  panOnDrag={false}
/>

6. useZoomPanHelper transform - useReactFlowに統合

「transform」はストア内の変換の変数名でもあるため、transformがセッターであることが明確ではないため、setViewportに名前を変更しました。これは他の関数ともより整合性があります。また、すべてのuseZoomPanHelper関数は、useReactFlowフックまたはonInitハンドラーから取得するReact Flowインスタンスに移動されました。

古いAPI

const { transform, setCenter, setZoom  } = useZoomPanHelper();
...
transform({ x: 100, y: 100, zoom: 2 });

新しいAPI

const { setViewport, setCenter, setZoom } = useReactFlow();
...
setViewport({ x: 100, y: 100, zoom: 2 });

新しいビューポート関数

  • getZoom
  • getViewport

7. isHidden - hidden

プレフィックス付き(is...)とプレフィックスなしのブール値オプション名を混在させていました。すべてのノードとエッジのオプションには、プレフィックスが付けられなくなりました。そのため、hiddenanimatedselecteddraggableselectableconnectableとなります。

古いAPI

const hiddenNode = { id: '1', isHidden: true, position: { x: 50, y: 50 } };

新しいAPI

const hiddenNode = { id: '1', hidden: true, position: { x: 50, y: 50 } };

8. arrowHeadType markerEndId - markerStart / markerEnd

エッジのマーカーをカスタマイズするためのAPIを改善しました。新しいAPIを使用すると、エッジの先頭と末尾に個々のマーカーを設定し、色、strokeWidthなどでカスタマイズできます。markerEndIdを設定することもできますが、異なるプロパティを使用する代わりに、markerStartmarkerEndプロパティは、文字列(自分で定義する必要があるsvgマーカーのID)または組み込みのarrowclosedまたはarrowマーカーを使用するための構成オブジェクトのいずれかを受け入れます。

古いAPI

const markerEdge = { source: '1', target: '2', arrowHeadType: 'arrow' };

新しいAPI

const markerEdge = {
  source: '1',
  target: '2',
  markerStart: 'myCustomSvgMarker',
  markerEnd: { type: 'arrow', color: '#f00' },
};

9. ArrowHeadType - MarkerType

これは、マーカーAPIをより一貫性のあるものにするための言葉の変更にすぎません。今ではエッジの先頭にマーカーを設定できるようになったため、ArrowHeadTypeという名前のタイプはMarkerTypeに名前が変更されました。将来的には、矢印の形状だけでなく、円、菱形なども含めることができます。

10. 属性表示

これはAPIに対する破壊的な変更ではありませんが、React Flowの一般的な外観に小さな変更があります。「React Flow」という小さな属性表示が右下に追加されました(位置はattributionPositionプロパティで設定できます)。この変更は、新しい「React Flow Pro」サブスクリプションモデルに伴うものです。商用アプリケーションで属性表示を削除する場合は、「React Flow Pro」を購読してください。