Open8
React Flowの公式ドキュメントを翻訳しつつ、サンプルを実装してみる

Introduction
- React Flowは、ノードベースのアプリケーションを構築するためのライブラリ
- シンプルな静的ダイアグラムからデータのビジュアライゼーション、複雑なビジュアルエディターなどが作成可能
Key Features
使いやすさ: React Flowには、すぐに使える多くの機能がすでに備わっている。
ノードのドラッグ、ズームとパン、複数のノードとエッジの選択、エッジの追加と削除はすべてビルトインされている。
カスタマイズ可能: React Flowは、カスタムノードタイプとカスタムエッジタイプをサポートしている。
カスタムノードは単なるReactコンポーネントなので、ビルトインのノードタイプに縛られることなく、必要なものを何でも実装可能。
高速レンダリング: React Flowは、変更されたノードだけをレンダリングし、ビューポートにあるノードだけが表示されるようにしている。
組み込みのプラグイン: React Flowには、いくつかのプラグインが存在する
信頼性が高い: React Flowは、バグを早期に発見し、簡単に修正できるように、すべてTypeScriptで書かれている。
それ以外の部分については、堅牢なcypressテストスイートが用意されているので、安心してReact Flowに依存すること可能

Terms and Definitions
- React Flowでよく利用されるものは、ノード、エッジ、ハンドルの3つ。
Nodes
- React FlowのノードはReactコンポーネント
- ノードはx座標とy座標があり、ビューポート内のどこに配置されるかの情報
- ノードをカスタマイズするためのオプションは Node optionsに記載
Custom Nodes
- ノードをカスタマイズして見た目や動作を自由に変えることが可能
- フォーム要素のレンダー
- データの視覚化
- 複数ハンドルのサポート
- 詳しくは custom node docsに記載
Handles
- ハンドルは、エッジがノードに接続される場所のことを示す
- ハンドルはどこにでも付けられ、好みのスタイルにアレンジ可能
- デフォルトでは、ノードの上下左右に灰色の円として表示される
- カスタム ノードを作成するときは、ノード内に必要な数のハンドルを含めることができる
- 詳しくは handle docsに記載
Edge
- エッジは2つのノードを接続するもの
- すべてのエッジにはターゲットノードとソースノードが必要
- React Flow には、デフォルト、スムーズステップ、ステップ、ストレートの4つの組み込みエッジタイプが存在する
- エッジは、CSSでスタイル設定でき、完全にカスタマイズ可能な SVG パス
- 複数のハンドルを仕様している場合は、個別に参照してノードに複数の接続を作成することが可能
Custom Edge
- カスタムノードと同様にエッジもカスタマイズ可能
- エッジを削除するボタンを追加
- カスタムルーティング動作
- 1 つの SVG パスだけでは解決できない複雑なスタイルやインタラクション
- 詳しくは custom edges apiに記載
Connection Line
- React Flow には、新しいエッジを作成するために、あるハンドルから別のハンドルまでクリックアンドドラッグする機能が組み込まれている
- ドラッグ中のプレースホルダーのエッジは接続線と呼ばれる
- 接続線も4種類存在しておりカスタマイズ可能
- 詳しくは props sectionに記載
Viewport
- React Flow のすべてはビューポート内に存在する。
- ビューポートには、x、y、およびズーム値が設けられている
- ペインをドラッグするとX座標とY座標が変更され、ズームインまたはズームアウトするとズームレベルが変更される

Core Concepts
- フローはノードとエッジ (またはノードのみ) で構成される
- ノードとエッジの配列をpropsとして ReactFlow コンポーネントに渡すことができる
- すべてのノードIDとエッジIDは一意である必要がある
- ノードには位置とラベルが必要であり(カスタム ノードを使用している場合は異なる可能性がある)、エッジにはソース(ノード ID)とターゲット(ノード ID)が必要
Controlled or Uncontrolled
- React Flowでは、フローをセットアップする2つの方法があり、制御されたものまたは制御されていないもののいずれかを作成できる
Basic Functionality
- デフォルトでは、React Flow は制御されたフローをセットアップするときにビューポートを処理する以外に内部状態の更新を行わない
- <input /> コンポーネントと同様に、React Flow によってトリガーされた変更をノードとエッジに適用するハンドラーを渡す必要がある
- ノードとエッジを選択、ドラッグ、削除するには、onNodesChange ハンドラーと onEdgesChange ハンドラーを実装する必要がある
- applyNodeChanges ハンドラーは、新しいノード配列である更新されたノード配列を返す
- onNodesChangeとonEdgesChangeハンドラーはそれぞれ、useNodesStateとuseEdgesStateからエクスポートできる
Connecting Nodes
- 例では新しく作成されたエッジを含むエッジの配列を返す addEdge ハンドラーを使用している

Panning and Zooming
- React Flow のデフォルトのパンとズームの動作は、スリッピー マップ (新しいタブで開きます) からインスピレーションを得ている
- 提供されたprops を使用して、この動作を簡単にカスタマイズ可能
Default Viewport Controls
- デフォルトのコントロールは次のとおり
- pan: drag mouse
- zoom: scroll
- create selection: Shift + drag
Figma-like Viewport Controls
- figma/sketch/design ツールのコントロールを希望する場合は、panOnScroll={true} およびselectionOnDrag={true} を設定できる

Plugin Components
MiniMap
- フローが大きくなると、概要をすぐに把握したい場合があり、このために、MiniMap コンポーネントを構築。子として追加することで、フローに簡単に追加可能。
Controls
- React Flow にはカスタマイズ可能なコントロール バーが付属しており、Controls コンポーネントをインポートすることで使用できる。
Background
- パターンの背景を表示したい場合は、Background コンポーネントを使用可能。
Panel
- React Flow ビューポートの上にコンテンツを表示するヘルパーコンポーネント。

Custom Nodes
- React Flowの強力な機能は、カスタムノードを追加できる。
- カスタムノード内では、好きなものをすべてレンダリングできる。例えば、複数のソースハンドルとターゲットハンドルを定義して、フォーム入力やグラフをレンダリングできる。
Implementing the Custom Node
- カスタムノードは、選択やドラッグなどの基本的な機能を提供するためにラップされた React コンポーネント
- ラッパーコンポーネントからは、他のプロパティに加えて、位置やデータなどのプロパティも渡す
Adding the Node Type
- nodeTypesをpropに追加することで、React Flowに新しいノードタイプを追加できる。
- nodeTypesがメモ化されているか、コンポーネントの外部で定義されていることが重要。
- そうしないと、Reactはレンダリングのたびに新しいオブジェクトを作成し、パフォーマンスの問題やバグにつながる。
- 新しいノードタイプを定義した後、typeノードオプションを使用してそれを使用できる。
Using Multiple Handles
- 特定のハンドルで他のノードを接続したい場合は、ノードIDだけでは不十分で、特定のハンドルIDも渡す必要がある。
- ハンドル固有のエッジは、ノード内のハンドルを参照する sourceHandle または targetHandle オプションを使用する。
- カスタムノードのハンドルの位置または数をプログラムで変更している場合はuseUpdateNodeInternals フックを使用して変更を ReactFlow に適切に通知する必要があることに注意。

Custom edges
- カスタムノードと同様、React Flow のカスタム エッジの一部は単なる React コンポーネント
- つまり、エッジに沿って必要なものを何でもレンダリング可能
A basic custom edge
- 接続された 2 つのノード間のパスをレンダリングしない場合、エッジはあまり役に立たない
- これらのパスは常に SVG ベースであり、通常は <BaseEdge /> コンポーネントを使用してレンダリングされる
- レンダリングする実際の SVG パスを計算するために、React Flow にはいくつかの便利なユーティリティ関数が付属してる
- getBezierPath
- getSimpleBezierPath
- getSmoothStepPath
- getStraightPath
- カスタムエッジを開始するには、ソースとターゲット間の直線パスをレンダリングするのみ
- カスタムエッジコンポーネントに渡されるすべての props は、API リファレンスの EdgeProps タイプ参照
- 使用するには、 <ReactFlow /> コンポーネントのedgeTypes propを更新する必要もある
- 不要な再レンダリングを防ぐために、コンポーネントの外側でedgeTypes オブジェクトを定義するか、React の useMemo フックを使用することが重要。これを忘れた場合、React Flow はコンソールに警告を表示する
- EdgeTypes オブジェクトを定義した後、エッジのタイプフィールドを「custom-edge」に設定することで、新しいカスタムエッジを使用できる
Adding an edge label
- カスタム エッジのより一般的な用途の 1 つは、エッジのパスに沿っていくつかのコントロールや情報をレンダリングすること
- React Flow では、これをエッジラベルと呼び、エッジパスとは異なり、エッジラベルは任意の React コンポーネントにすることができる
- カスタムエッジラベルをレンダリングするには、それを <EdgeLabelRenderer /> コンポーネントでラップする必要がある
- これはパフォーマンス上の理由から必要で、エッジラベルレンダーは、すべてのエッジラベルがレンダリングされる単一のコンテナへのポータル

Theming
- React Flow は、深いカスタマイズを念頭に置いて構築されている
- ユーザーの多くは、React Flow の外観と雰囲気を自分のブランドやデザインシステムに合わせて完全に変更している
Default styles
- React Flow のデフォルトスタイルは、組み込みノードを使用するには十分。
- これらは、パディング、境界線の半径、アニメーション化されたエッジなどのスタイルにいくつかの適切なデフォルトを提供する
- 通常、これらのデフォルトスタイルは、App.jsx ファイルまたは他のエントリポイントにインポートすることによって読み込まれる
import '@xyflow/react/dist/style.css';
-
カスタムノードやエッジを使用せずに、React Flow の基本的な外観をスタイル設定するには 3 つの方法がある
- style propsを介して、インラインスタイルを提供する
- カスタム CSS による組み込みクラスのオーバーライド
- React Flow が使用する CSS 変数をオーバーライドする
- ダークモードの例にあるように、colorMode プロパティ ('dark'、'light'、または 'system') を使用して、組み込みのカラー モードの 1 つを選択できる
- colorMode プロパティを使用すると、React Flow は、カラーモードに基づいてフローのスタイルを設定するために使用できるクラスをルート要素 (.react-flow) に追加する
- フローの外観と雰囲気のカスタマイズを開始する最も簡単な方法は、React Flow のコンポーネントの多くにあるスタイルpropsを使用して独自の CSS をインライン化すること
- デフォルトのスタイルを完全に置き換えるのではなく、全体的な外観と雰囲気を微調整したいだけの場合は、ライブラリ全体で使用する CSS 変数の一部をオーバーライドできる
- これらの変数は、React Flow のさまざまな要素のデフォルトを定義するために使用される。これは、インラインスタイルまたはカスタム クラスによって要素ごとにオーバーライドできることを意味する
- インラインスタイルの多用はアンチパターンであると考える人もいる
- その場合、React Flow が使用する組み込みクラスを独自の CSS でオーバーライドできる
- React Flow にはあらゆる種類の要素に多数のクラスが関連付けられていますが、オーバーライドする可能性が高いクラスを以下に示す
- オーバーライドする他のクラスを探してソースコードを探索する場合は注意する。一部のクラスは内部で使用され、ライブラリが機能するために必要で、置き換えると、予期しないバグやエラーが発生する可能性がある