Flow Studio
React Flow Sync
workflowStore is the master. React Flow renders whatever the store says. User interactions on the canvas (drag, connect, delete) write back to workflowStore via React Flow's callback props — completing the sync loop.
The Sync Architecture
[workflowStore] ──(nodes, edges, viewport)──► [ReactFlow component renders]
▲ │
│ │ User interaction
│ (drag, connect, delete, pan)
│ ▼
└────────────── (onNodesChange, onEdgesChange, onConnect, onMoveEnd) ─────
WorkflowCanvas — The Sync Bridge
// WorkflowCanvas.tsx (simplified)
import ReactFlow, { useReactFlow } from 'reactflow';
import { useWorkflowStore } from '@flow-studio/services';
export function WorkflowCanvas() {
const { nodes, edges, moveNode, addEdge, removeNode, setViewport } =
useWorkflowStore(state => ({
nodes : state.nodes,
edges : state.edges,
moveNode : state.moveNode,
addEdge : state.addEdge,
removeNode: state.removeNode,
setViewport: state.setViewport
}), shallow);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodeDragStop={(_, node) => moveNode(node.id, node.position)}
onConnect={connection => addEdge({
id: crypto.randomUUID(),
source: connection.source!, sourceHandle: connection.sourceHandle!,
target: connection.target!, targetHandle: connection.targetHandle!
})}
onNodesDelete={nodes => nodes.forEach(n => removeNode(n.id))}
onEdgesDelete={edges => edges.forEach(e => removeEdge(e.id))}
onMoveEnd={(_, viewport) => setViewport(viewport)}
/>
);
}
Why workflowStore is the Master
React Flow has its own internal state. If we let React Flow be the source of truth, the store would need to read from React Flow — creating an inverted dependency. Instead:
- workflowStore is the single source of truth — always.
- React Flow receives
nodesandedgesas props — it renders whatever the store says. - When the user interacts, React Flow fires callbacks — we write those changes to the store.
- The store update triggers a React re-render — React Flow re-renders with the new state.
Controlled vs. Uncontrolled React Flow
| Mode | Source of Truth | Used in Flow Studio? |
|---|---|---|
| Uncontrolled | React Flow internal state | No |
| Controlled | External state (workflowStore) | Yes |
Do not mix controlled and uncontrolled patterns. If you pass
nodes as a prop (controlled) but also call React Flow's internal setNodes directly, you will get state divergence — the canvas will show different nodes than the store holds. Always go through workflowStore actions.