学習React Flowのカスタマイズ

カスタムノード

React Flowの強力な機能の1つは、カスタムノードを追加できることです。カスタムノード内では、必要なものをすべてレンダリングできます。複数のソースハンドルとターゲットハンドルを定義し、たとえばフォーム入力やチャートをレンダリングできます。このセクションでは、アプリケーションの別の部分のテキストを更新する入力フィールドを持つノードを実装します。

カスタムノードの実装

カスタムノードは、選択やドラッグなどの基本的な機能を提供するためにラップされたReactコンポーネントです。ラッパーコンポーネントからは、位置やデータなどのプロパティに加えて、他のプロパティも渡されます。TextUpdaterNodeの実装を始めましょう。Handleコンポーネントを使用して、カスタムノードを他のノードに接続し、ノードに入力フィールドを追加します

import { useCallback } from 'react';
import { Handle, Position } from '@xyflow/react';
 
const handleStyle = { left: 10 };
 
function TextUpdaterNode({ data }) {
  const onChange = useCallback((evt) => {
    console.log(evt.target.value);
  }, []);
 
  return (
    <>
      <Handle type="target" position={Position.Top} />
      <div>
        <label htmlFor="text">Text:</label>
        <input id="text" name="text" onChange={onChange} className="nodrag" />
      </div>
      <Handle type="source" position={Position.Bottom} id="a" />
      <Handle
        type="source"
        position={Position.Bottom}
        id="b"
        style={handleStyle}
      />
    </>
  );
}

ご覧のとおり、入力にクラス名「nodrag」を追加しました。これにより、入力フィールド内でのドラッグが防止され、たとえばテキストを選択できます。

ノードタイプの追加

nodeTypesプロパティに追加することで、React Flowに新しいノードタイプを追加できます。**nodeTypesはメモ化されるか、コンポーネントの外部で定義されることが重要です。**そうでない場合、Reactはレンダリングごとに新しいオブジェクトを作成し、パフォーマンスの問題やバグが発生します。

const nodeTypes = useMemo(() => ({ textUpdater: TextUpdaterNode }), []);
 
return <ReactFlow nodeTypes={nodeTypes} />;

新しいノードタイプを定義したら、typeノードオプションを使用して使用できます

const nodes = [
  {
    id: 'node-1',
    type: 'textUpdater',
    position: { x: 0, y: 0 },
    data: { value: 123 },
  },
];

すべてをまとめて基本的なスタイルを追加すると、コンソールにテキストを出力するカスタムノードが完成します

export default function App() {
  const data: string = "world"

  return <h1>Hello {data}</h1>
}

読み取り専用

複数のハンドルの使用

ご覧のとおり、ノードに2つのソースハンドルを追加して、2つの出力を持つようにしました。他のノードをこれらの特定のハンドルに接続する場合、ノードIDだけでは不十分で、特定のハンドルIDも渡す必要があります。この場合、一方のハンドルはID "a"を持ち、もう一方は"b"を持ちます。ハンドル固有のエッジは、ノード内のハンドルを参照するsourceHandleまたはtargetHandleオプションを使用します

const initialEdges = [
  { id: 'edge-1', source: 'node-1', sourceHandle: 'a', target: 'node-2' },
  { id: 'edge-2', source: 'node-1', sourceHandle: 'b', target: 'node-3' },
];

この場合、ソースノードは両方のハンドルでnode-1ですが、ハンドルIDは異なります。1つはハンドルID "a"から、もう1つは"b"からです。両方のエッジにも異なるターゲットノードがあります

export default function App() {
  const data: string = "world"

  return <h1>Hello {data}</h1>
}

読み取り専用

カスタムノードでハンドルの位置または数をプログラムで変更する場合は、useUpdateNodeInternalsフックを使用して、ReactFlowに変更を適切に通知する必要があります。ここから、カスタムノードを構築できるはずです。ほとんどの場合、カスタムノードのみを使用することをお勧めします。組み込みのものは単なる基本的な例です。渡されるプロパティのリストと詳細については、カスタムノードAPIセクションを参照してください。