Files
zui/PERFORMANCE.md
2026-03-08 20:53:34 +01:00

3.5 KiB
Raw Blame History

Performance notes

Already in place

  • Throttled node updates during drag onNodesChange merges changes and flushes at most once per animation frame (~60 fps) so dragging doesnt trigger hundreds of re-renders per second.
  • nodeDragThreshold={1} Avoids treating small pointer moves as drags and reduces noisy change events.
  • Memoized React Flow props nodeTypes, edgeTypes, defaultEdgeOptions, and flowContextValue are memoized so their references dont change every render.
  • Custom nodePropsAreEqual Node components use React.memo(..., nodePropsAreEqual) so a node only re-renders when its own id, data, width, height, or selected change (e.g. dragging one node doesnt force others to re-render when the library keeps their props reference stable).
  • ConfigNode derived data incomingEdges, incomingIds, and connected* are wrapped in useMemo so they arent recomputed on every render.

Further improvements you can try

1. Split context (medium effort)

Right now every component that uses useContext(FlowContext) re-renders whenever nodes or edges change. You can split into:

  • FlowDataContext nodes, edges (changes often).
  • FlowActionsContext setNodes, setEdges, isValidConnection, etc. (stable).

Components that only need actions (e.g. menus, buttons) subscribe to FlowActionsContext and wont re-render on graph updates.

2. Avoid reading full nodes/edges where possible

React Flows docs recommend not depending on the full nodes/edges arrays when you only need a small slice (e.g. “selected ids”). If you add features like selection state, keep that in a separate store or state (e.g. selectedNodeIds) and have components depend on that instead of filtering nodes everywhere.

3. Lighter node content

  • CodeMirror Config and function nodes use CodeMirror; its heavy. Options: lazy-initialize the editor (mount only when the node is focused or visible), or use a plain <textarea> for very small/simple flows.
  • Resize NodeResizeControl and useResizeHeight add work. If you dont need resize everywhere, make it optional or only on certain node types.

4. CSS

  • Containment BaseNode already uses contain: layout where dimensions are set. Keeping layout/paint contained per node helps.
  • Simpler styles For many nodes, avoid heavy shadows, blur, or complex animations on the node container; they can cost a lot during pan/zoom/drag.

5. RenderingNode pipeline

The render node runs Nunjucks + Kroki on signatures (config, edges, variables, functions). It already avoids re-running when irrelevant data changes. If you add more inputs, keep them in the signature pattern so the effect only runs when something that affects the result actually changes.

6. Large graphs

  • Hide/collapse For big trees, use the hidden property (or similar) so only expanded nodes are rendered.
  • Virtualization React Flow doesnt virtualize by default. For 100+ nodes, consider only rendering nodes in view (e.g. with onlyRenderVisibleElements if/when available in your version) or a custom viewport-based filter.

7. Build / runtime

  • Production build Use vite build and test with the production build; React and Vite are much faster without dev mode and source maps.
  • React DevTools Profiler Record while dragging or editing to see which components re-render and how often; that will guide where to add more memoization or split context.