Comprehensive React Flow (@xyflow/react) patterns and best practices for building node-based UIs, workflow editors, and interactive diagrams. Use when working with React Flow for (1) building flow editors or node-based interfaces, (2) creating custom nodes and edges, (3) implementing drag-and-drop workflows, (4) optimizing performance for large graphs, (5) managing flow state and interactions, (6) implementing auto-layout or positioning, or (7) TypeScript integration with React Flow.
95
95%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
When you only need data from specific nodes, use useNodesData() instead of useNodes() to avoid unnecessary re-renders.
Incorrect (inefficient - re-renders on any node change):
function NodeCounter() {
const nodes = useNodes(); // ❌ Re-renders when ANY node changes
const selectedNode = nodes.find(n => n.selected);
return <div>Selected: {selectedNode?.data.label}</div>;
}
// If you have 100 nodes and change one unrelated node,
// this component still re-renders unnecessarilyCorrect (efficient - only re-renders when specific node changes):
import { useNodesData } from '@xyflow/react';
function NodeDisplay({ nodeId }: { nodeId: string }) {
// ✅ Only re-renders when this specific node's data changes
const nodeData = useNodesData(nodeId);
if (!nodeData) return <div>Node not found</div>;
return <div>{nodeData.label}: {nodeData.value}</div>;
}Multiple Specific Nodes:
function MultiNodeDisplay({ nodeIds }: { nodeIds: string[] }) {
// ✅ Only re-renders when these specific nodes change
const nodesData = useNodesData(nodeIds);
return (
<div>
{nodesData.map((data, index) => (
<div key={nodeIds[index]}>
{data?.label || 'Unknown'}
</div>
))}
</div>
);
}When to Use Each Hook:
// Use useNodes when you need:
// - All nodes
// - To iterate over all nodes
// - To count total nodes
const allNodes = useNodes();
const nodeCount = allNodes.length;
// Use useNodesData when you need:
// - Specific node(s) data
// - To avoid re-renders from unrelated node changes
const nodeData = useNodesData('node-id');
// Use useReactFlow when you need:
// - Methods to manipulate nodes (getNode, setNodes, addNodes, etc.)
// - One-time reads without subscribing to changes
const { getNode, setNodes } = useReactFlow();Performance Comparison:
// Scenario: 500 nodes, user drags one node
// ❌ useNodes - re-renders on every position update (poor performance)
function BadComponent() {
const nodes = useNodes();
const myNode = nodes.find(n => n.id === 'my-node');
return <div>{myNode?.data.label}</div>;
}
// ✅ useNodesData - only re-renders if 'my-node' changes (good performance)
function GoodComponent() {
const nodeData = useNodesData('my-node');
return <div>{nodeData?.label}</div>;
}Additional Context:
useNodesData returns the data property of nodes, not the full node objectnull if node doesn't existuseEdges vs selective subscriptionsReference: useNodesData Hook