Learn React Flow and how to add real-time sync between participants
Tags: react, eventdriven, javascript, reactflow
Published: 2024-04-23 16:11:44

Today I want to present to you this powerful tool for creating a node-based application: the [React Flow](https://superviz.com/react-flow/). It is a library for building anything from simple static diagrams to data visualizations to complex visual editors. In this article I will show you how to create a simple React Flow application, understand more about nodes and edges, and add real-time synchronization between participants in the same content.

## Installation

To begin with React Flow, you first will need to have a React base application and add the package `reactflow` to it, you can use any package manager

```jsx
npm install reactflow
```

## Nodes and Edges

Before starting to use it, you should be familiarized with what a node and an edge is.  

In simple terms, nodes are the primary elements or objects that you want to represent in your graph, and edges are the connections or relationships between these nodes. For example, in a social network, each person could be a node, and the friendships between them could be the edges.

Technically speaking, React Flow has these two types: the [Node](https://reactflow.dev/api-reference/types/node), which will contain an ID, a position and its data, and the [Edge](https://reactflow.dev/api-reference/types/edge) which will contain an ID for it, a source and target. In the code below I created a list of initial nodes (a couple of blocks) and a list of initial edges: connecting the first node to the second node.

```jsx
export const initialNodes = [
	{
		id: '1',
		position: { x: 200, y: 200 },
		data: { label: 'First block' },
	},
	{ 
		id: '2', 
		position: { x: 250, y: 300 }, 
		data: { label: 'Second block' } 
	},
]

export const initialEdges = [ 
	{
		id: 'some-id', 
		source: '1', 
		target: '2' 
	}
]

```

## Start using React Flow

After creating the initial nodes and edges, you are now able to add the `ReactFlow` component to your application. Such as shown below:

```jsx
import React from 'react';
import ReactFlow from 'reactflow';
 
import 'reactflow/dist/style.css';
 
export default function App() {
  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <ReactFlow nodes={initialNodes} edges={initialEdges} />
    </div>
  );
}
```

In the code above we create a full screen container for our nodes. We also import the styles from  `reactflow/dist/style.css`.

To make manipulation of the data easy, I’m going to use the [`useNodesState`](https://reactflow.dev/api-reference/hooks/use-nodes-state) and [`useEdgesState`](https://reactflow.dev/api-reference/hooks/use-edges-state) hooks, which work like the `useState` hook. With an addiction to a callback function when there are changes on the state.

```jsx
import ReactFlow, { useNodesState, useEdgesState } from 'reactflow'

export default function App() {
	const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes)
	const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges)

  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <ReactFlow nodes={nodes} edges={edges} />
    </div>
  );
}
```

To create a better experience for our users, let’s add some controls, allowing them to zoom in and out, to see a mini map of their content and other features. We will add it as a child to our `ReactFlow` component.

```jsx
<ReactFlow nodes={nodes} edges={edges}>
	<Controls />
	<MiniMap />
</ReactFlow>
```

To make a great background, you can also add the Background element, in which you will be able to choose variants of background like dots, crosses or lines as well their colors.

```jsx
<Background variant={BackgroundVariant.Cross} color='#f00' />
```

## Synchronizing between users

If you want to create a collaborative environment where multiple users can interact with the same React Flow application at the same time, you will need to use a [Real-time Data Engine](https://docs.superviz.com/sdk/presence/real-time-data-engine). This engine allows any changes made by one user to be instantly visible to all other users in the same room. This involves creating a unique room for each group of users and synchronizing their activities.

### Creating a shared room

A room is a virtual space where users can join and collaborate. When creating a room, you can specify a unique ID for it.

To create a room, you need to use the `SuperVizRoom` that’s available from the `@superviz/sdk` package, which takes the Developer Key and an object as a parameter. The object should have the following properties:

- `id`: The ID of the room, which should be a unique string shared between the participants of that room.
- `participant`: An object that contains information about the current user, such as `name`, `id`.
- `group`: An object that contains information about the group that the user belongs to, such as `name` and `id`.

Here’s an example of how to create a room with SuperViz:

```jsx
// Import the SuperViz SDK
import SuperVizRoom from '@superviz/sdk';

// Create a room object
const room = await SuperVizRoom(DEVELOPER_KEY, {
  roomId: "<ROOM-ID>",
  participant: {
    id: "<USER-ID>",
    name: "<USER-NAME>"
  },
});
```

### Adding the Real-time Data Engine

To add the event broker, which will be responsible for notifying when a change is made and to listen to state changes. Right after creating a room, you can add the engine to it.

```jsx
const realtime = new Realtime();
room.addComponent(realtime);
```

### Listening to state changes

To make full synchronization we are going to listen to a couple of events: `new-edge` and `node-drag`, which happens when we connect one React Flow node to another and when we drag a node across the canvas. 

Let’s first create a function to handle when new edges are added, and then subscribe it to the `new-edge` event.

```tsx
function onNewEdgesAdded({data, participantId}){
  // Verify if the origin of the event dispatch isn't the same participant on the page
  // preventing a infinity loop
	if (participantId === currentParticipantId) return;

  setEdges((eds) => addEdge(data.edge, eds));
}

realtime.subscribe('new-edge', onNewEdgesAdded)
```

Now, we will do something similar to listening to `node-drag`. In this code we will update our nodes with the data, containing its new position, that we receive from the event.

```tsx
function onNodeDragEventHandler({data, participantId}){
	// Verify if the origin of the event dispatch isn't the same participant on the page
  // preventing a infinity loop
	if (participantId === currentParticipantId) return;

	setNodes((nodes: { id }[]) =>
		nodes.map((node: { id }) => (node.id === data.node.id ? data.node : node))
	);
}

realtime.subscribe('node-drag', onNodeDragEventHandler)
```

### Publishing an event

We are now listening to the events, but to trigger these events, we need to publish them. We can do this by using the `publish` method from the `realtime` object. Whenever a user adds a new edge or drags a node, we will call `realtime.publish`, passing the name of the event and the relevant data. This will then trigger the corresponding event listeners in other users' applications, keeping all participants in sync.

To understand when new changes are made on both scenarios, we need to use React Flow’s callback functions `onConnect` and `onNodeDrag`, such as the code below:

```tsx
<ReactFlow
	...
	onNodeDrag={onNodeDrag}
	onConnect={onConnect}>
</ReactFlow>
```

The implementation of the `onNodeDrag` is straightforward, as shown below:

```tsx
function onNodeDrag(event, node) {
	realtime.publish('node-drag', { node });
}
```

To publish the `new-edge` event on a new connection (`onConnect`) it's a bit different, we first need to recreate the edge object, add it to our current list using the React Flow’s `addEdge` method, and then publish to the Real-time Data Engine.

```tsx
function onConnect(params) => {
	const edge = {
		...params,
		type: ConnectionLineType.SmoothStep,
		animated: true,
	}

	setEdges((edges) => addEdge(edge, edges))

	realtime.publish('new-edge', { edge })
}
```

### Conclusion

In this tutorial, we've learned the basics of [React Flow](https://superviz.com/react-flow/) and how to create a real-time, collaborative environment using SuperViz's [Real-time Data Engine](https://docs.superviz.com/sdk/presence/real-time-data-engine). You can see this project in functioning on our [demo page dedicated](https://docs.superviz.com/demos/react-flow) to React Flow, as well the [source code on our GitHub repository](https://github.com/SuperViz/demos/tree/main/react-flow).

Happy coding!