CtrlK
BlogDocsLog inGet started
Tessl Logo

gedsys/react-flow-usage

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

Quality

95%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

hook-use-nodes-data.mdrules/

title:
Use useNodesData Instead of useNodes for Specific Nodes
impact:
MEDIUM
impactDescription:
useNodes causes re-renders on any node change; useNodesData only re-renders when specified nodes change
tags:
react-flow, hooks, performance, optimization

Use useNodesData Instead of useNodes for Specific Nodes

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 unnecessarily

Correct (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 object
  • Returns null if node doesn't exist
  • Can pass a single ID string or an array of IDs
  • Significantly reduces re-renders in components that only need specific node data
  • Similar pattern exists for edges with useEdges vs selective subscriptions

Reference: useNodesData Hook

rules

_sections.md

_template.md

edge-connection-validation.md

hook-use-nodes-data.md

interaction-drag-drop.md

layout-auto-dagre.md

node-custom-handles.md

perf-memo-custom-components.md

setup-imports-css.md

setup-nodetypes-outside.md

state-save-restore.md

typescript-typed-nodes-edges.md

ALL_LINKS.md

README.md

SKILL.md

tile.json