最近、フロントエンドも触る必要があり、ReactとTypeScriptを触り始めました。このメモではReactのコンポーネントの一つであるReact Flow
をの使い方をメモしておきます。
【公式ページ】
【GitHubページ】 github.com
1)新しいReactプロジェクトの作成(TypeScript対応)
$ npx create-react-app my-flow-app --template typescript $ cd my-flow-app/
以下のように表示されればプロジェクトのテンプレートの作成に成功しています。
Success! Created my-flow-app at /home/user2404/my-flow-app Inside that directory, you can run several commands:
作成されたディレクトリは以下のようになっています。
$ ls -al total 704 drwxr-xr-x 5 user2404 user2404 4096 Nov 1 12:57 . drwxr-x--- 16 user2404 user2404 4096 Nov 1 12:56 .. -rw-r--r-- 1 user2404 user2404 310 Nov 1 12:57 .gitignore -rw-r--r-- 1 user2404 user2404 2117 Nov 1 12:57 README.md drwxr-xr-x 885 user2404 user2404 36864 Nov 1 13:03 node_modules -rw-r--r-- 1 user2404 user2404 645580 Nov 1 13:03 package-lock.json -rw-r--r-- 1 user2404 user2404 1001 Nov 1 13:03 package.json drwxr-xr-x 2 user2404 user2404 4096 Nov 1 12:57 public drwxr-xr-x 2 user2404 user2404 4096 Nov 1 12:57 src -rw-r--r-- 1 user2404 user2404 535 Nov 1 12:57 tsconfig.json
2)パッケージのインストール
プロジェクトディレクトリができたら必要となるreactflow
のパッケージをインストールします。
$ npm install reactflow
【メモ】npxコマンド
とnpmコマンド
の違い
npxコマンド
はNode Package Executeの略で、Node.js
に付属するコマンドラインツールです。開発環境に多くのコマンドをインストールせず、環境を整えることができるというようなものです。
npxコマンド
の主な特徴
- パッケージをインストールせずに一時的に実行できる
- ローカルにインストールされたパッケージを簡単に実行できる
- インストールしないため、常に最新バージョンのパッケージを使用可能
3)ファイルの編集(追加・修正)
作成時のテンプレートディレクトリは以下の様になっています。
オリジナルのテンプレートのファイルツリー
my-flow-app/ ├── src/ │ ├── App.tsx # メインのアプリケーションコンポーネント │ ├── App.css │ ├── index.tsx │ └── ... ├── package.json └── ...
編集手順
ここから以下の作業を行います。
BasicFlow.tsx
の作成App.tsx
の修正 …BasicFlow.tsx
を取り込むApp.css
の修正 … CSSの記述を追加
1.BasicFlow.tsxの作成
【my-flow-app/src/components/BasicFlow.tsx】
import React, { useState, useCallback } from 'react'; import ReactFlow, { Node, Edge, Connection, addEdge, Background, Controls, MiniMap } from 'reactflow'; import 'reactflow/dist/style.css'; const initialNodes: Node[] = [ { id: '1', type: 'input', data: { label: 'Input Node' }, position: { x: 250, y: 25 }, }, { id: '2', data: { label: 'Default Node' }, position: { x: 100, y: 125 }, }, { id: '3', type: 'output', data: { label: 'Output Node' }, position: { x: 250, y: 250 }, }, ]; const initialEdges: Edge[] = [ { id: 'e1-2', source: '1', target: '2' }, { id: 'e2-3', source: '2', target: '3' }, ]; const BasicFlow = () => { const [nodes, setNodes] = useState<Node[]>(initialNodes); const [edges, setEdges] = useState<Edge[]>(initialEdges); const onConnect = useCallback( (connection: Connection) => { setEdges((eds) => addEdge(connection, eds)); }, [] ); return ( <div style={{ width: '100%', height: '500px' }}> <ReactFlow nodes={nodes} edges={edges} onConnect={onConnect} fitView > <Background /> <Controls /> <MiniMap /> </ReactFlow> </div> ); }; export default BasicFlow;
2. App.tsx
の修正 … BasicFlow.tsx
を取り込む
【my-flow-app/src/App.tsx】
import React from 'react'; import './App.css'; // ReactFlowのCSSをインポート import 'reactflow/dist/style.css'; //ReactFlowのコンポーネントをインポート import BasicFlow from './components/BasicFlow'; function App() { return ( <div className="App"> <h1>React Flow Chart Demo</h1> {/* ReacFlowのコンポーネントを配置 */} <div style={{ width: '100%', height: '600px', border: '1px solid #ccc' }}> <BasicFlow /> </div> </div> ); } export default App;
3. App.css
の修正 … CSSの記述を追加
【my-flow-app/src/App.css】
.App { text-align: center; } /* (追加部分)ReactFlowのスタイルをインポート */ @import 'reactflow/dist/style.css'; .App-logo { height: 40vmin; pointer-events: none; } @media (prefers-reduced-motion: no-preference) { .App-logo { animation: App-logo-spin infinite 20s linear; } } .App-header { background-color: #282c34; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); color: white; } .App-link { color: #61dafb; } @keyframes App-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
編集後のオリジナルのテンプレートのファイルツリー
my-flow-app/ ├── node_modules/ ├── public/ │ ├── index.html │ ├── favicon.ico │ └── ... ├── src/ │ ├── components/ │ │ └── BasicFlow.tsx # (作成)ReactFlowコンポーネント │ ├── App.tsx # (修正)メインアプリケーションファイル │ ├── App.css # (修正)スタイル │ ├── index.tsx # エントリーポイント │ └── ... ├── package.json ├── tsconfig.json # TypeScript設定 └── README.md
プログラムの実行
ファイルの編集が終わったら以下のように実行します。実行パスはプロジェクトのディレクトリで行ってください。
$ npm start
上記のように起動すると以下のような表示が行われます。
そして、ブラウザでhttp://localhost:3000
がタブで開きます。もし開かなかった場合にはコンソール上に表示されたURLにアクセスしても同様の結果を得る事ができます。
これで第一歩が完成しました。実行後にファイルの編集を行うと保存時に反映してくれるホットリロードの機能があるので、起動後はファイルを編集するだけで修正結果を確認出来ます。
ちょっとした説明
React Flow
は以下のコンポーネントを基本として構成されています。
基本的なコンポーネント
Node[]
… ノードの配列Edge[]
… エッジ(接続線)の配列ReactFlow
… メインコンポーネント
これらのコンポーネントを貼り付けることでグラフ構造を形作ります。Node
はノードつまり箱のような形をしたものになり、Edge
は箱同士を結ぶリンクとなります。これらのデータのリストを使用してReact Flow
はグラフを描画していきます。
Node[] コンポーネント
リストに各ノードの情報(属性)を格納していきます。基本的な属性としては以下のようなものがあります。
- id … ユニークなID(これを使用してEdgeの起点・終点を定義します)
- type … ノードの属性(コンポーネントの動きや色の指定などにも使ます)
- data … 情報(コンポーネントによってデータが異なる)
- position ... 座標値
今回の例では以下の3つのノードが存在しています。座標系に関してはReact Flow
コンポーネントの左上が(0,0)となっています。
const initialNodes: Node[] = [ { id: '1', type: 'input', data: { label: 'Input Node' }, position: { x: 250, y: 25 }, }, { id: '2', data: { label: 'Default Node' }, position: { x: 100, y: 125 }, }, { id: '3', type: 'output', data: { label: 'Output Node' }, position: { x: 250, y: 250 }, }, ];
Edge[] コンポーネント
リストに各エッジの情報(属性)を格納していきます。基本的な属性としては以下のようなものがあります。 基本的な属性としては以下のようなものがあります。
- id … ユニークなID
- source … 起点となるNodeのID
- target … 終点となるNodeのID
今回は以下の様になっています。特に座標値はなく、結ばれれるノードの座標情報を使用して描画が行われます。
const initialEdges: Edge[] = [ { id: 'e1-2', source: '1', target: '2' }, { id: 'e2-3', source: '2', target: '3' }, ];
コンポーネントのステート・コールバックを設定
ステート(コンポーネントの状態)とコールバック処理を設定しています。 今回のコールバック処理ではEdgeを追加する処理になっています。
const BasicFlow = () => { const [nodes, setNodes] = useState<Node[]>(initialNodes); const [edges, setEdges] = useState<Edge[]>(initialEdges); const onConnect = useCallback( (connection: Connection) => { setEdges((eds) => addEdge(connection, eds)); }, [] );
コンポーネントのReturn
設定したコンポーネントを返す処理をしています。先程のNode
、Edge
、コールバック処理(onConnect)
を値として渡しています。
return ( <div style={{ width: '100%', height: '500px' }}> <ReactFlow nodes={nodes} edges={edges} onConnect={onConnect} fitView > <Background /> <Controls /> <MiniMap /> </ReactFlow> </div> );
おわりに
ノードの編集機能や拡大縮小といった機能のない、もっともシンプルな形のグラフをReact Flow
で作成するメモでした。