Controlled or Uncontrolled
With React Flow you have two ways to setup a flow. You can either create a controlled or an uncontrolled one. We recommend to use a controlled one but for simpler use cases you can also setup an uncontrolled flow. In the following part we will setup a controlled flow. Let’s start by adding some nodes and edges to the ReactFlow component:
The dimensions of your React Flow component depend on the parent dimensions. That means that the parent needs a width and height to render React Flow properly.
import { useState } from 'react';
import { ReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
const initialNodes = [
{
id: '1',
type: 'input',
data: { label: 'Input Node' },
position: { x: 250, y: 25 },
},
{
id: '2',
// you can also pass a React component as a label
data: { label: <div>Default Node</div> },
position: { x: 100, y: 125 },
},
{
id: '3',
type: 'output',
data: { label: 'Output Node' },
position: { x: 250, y: 250 },
},
];
const initialEdges = [
{ id: 'e1-2', source: '1', target: '2' },
{ id: 'e2-3', source: '2', target: '3', animated: true },
];
function Flow() {
const [nodes, setNodes] = useState(initialNodes);
const [edges, setEdges] = useState(initialEdges);
return <ReactFlow nodes={nodes} edges={edges} fitView />;
}
export default Flow;
Uncontrolled Flow
There are two ways to use React Flow - controlled or uncontrolled. Controlled means, that you are in control of the state of the nodes and edges. In an uncontrolled flow the state of the nodes and edges is handled by React Flow internally. In this part we will show you how to work with an uncontrolled flow.
An implementation of an uncontrolled flow is simpler, because you don’t need to pass any handlers:
import { ReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { defaultNodes } from './nodes';
import { defaultEdges } from './edges';
const edgeOptions = {
animated: true,
style: {
stroke: 'white',
},
};
const connectionLineStyle = { stroke: 'white' };
export default function Flow() {
return (
<ReactFlow
defaultNodes={defaultNodes}
defaultEdges={defaultEdges}
defaultEdgeOptions={edgeOptions}
fitView
style={{
backgroundColor: '#D3D2E5',
}}
connectionLineStyle={connectionLineStyle}
/>
);
}
As you can see, we are passing defaultEdgeOptions
to define that edges are animated. This is helpful, because you can’t use the onConnect
handler anymore to pass custom options to a newly created edge. Try to connect “Node B” with “Node C” and you see that the new edge is animated.
Updating Nodes and Edges
Since you don’t have nodes and edges in your local state, you can’t update them directly. To do so, you need to use the React Flow instance that comes with functions for updating the internal state. You can receive the instance via the onInit
callback or better by using the useReactFlow
hook. Let’s create a button that adds a new node at a random position. For this, we are wrapping our flow with the ReactFlowProvider
and use the addNodes
function.
The Flow
component in this example is wrapped with the ReactFlowProvider
to use the
useReactFlow
hook.
import { useCallback } from 'react';
import { ReactFlow, ReactFlowProvider, useReactFlow } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { defaultNodes } from './nodes';
import { defaultEdges } from './edges';
const edgeOptions = {
animated: true,
style: {
stroke: 'white',
},
};
const connectionLineStyle = { stroke: 'white' };
let nodeId = 0;
function Flow() {
const reactFlowInstance = useReactFlow();
const onClick = useCallback(() => {
const id = `${++nodeId}`;
const newNode = {
id,
position: {
x: Math.random() * 500,
y: Math.random() * 500,
},
data: {
label: `Node ${id}`,
},
};
reactFlowInstance.addNodes(newNode);
}, []);
return (
<>
<ReactFlow
defaultNodes={defaultNodes}
defaultEdges={defaultEdges}
defaultEdgeOptions={edgeOptions}
fitView
style={{
backgroundColor: '#D3D2E5',
}}
connectionLineStyle={connectionLineStyle}
/>
<button onClick={onClick} className="btn-add">
add node
</button>
</>
);
}
export default function () {
return (
<ReactFlowProvider>
<Flow />
</ReactFlowProvider>
);
}