Conversation
React Flow passes each node component its position as props, so dragging a
node re-renders that node -- and its whole Mantine subtree -- on every pointer
move. Node components here read only `data`, `id` and, for the evaluator that
serves two node types, `type`, so a position change cannot change what they
render.
Wrap them in React.memo through a shared `memoNode` helper, comparing those
props alone. `data` compares by identity because the store never mutates it in
place under its old identity: `setDataPropsForNode` replaces it with a copy.
Measured on a production build, dragging one node for ~2.5s (Chrome CPU
profile, share of wall clock spent off-idle):
prompt node 47% -> 23% (1374 ms -> 546 ms)
table node 46% -> 22% (1079 ms -> 491 ms)
inspect node 26% -> 21% ( 561 ms -> 461 ms)
At ~23 ms of CPU per frame the prompt node could not hold 60fps while being
dragged; at ~9 ms it can.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue
React Flow passes each node component its position as props, so the node
being dragged re-renders its whole Mantine subtree on every pointer move.
None of the node components read the position -- they take only
{ data, id }, plus
typefor CodeEvaluatorNode, which serves two node types.Not the same as #458: that was a node subscribing to the whole nodes array,
so nodes standing still re-rendered. This is the dragged node re-rendering
itself, and it costs the same at 3 nodes as at 48.
Fix
A helper, src/memoNode.tsx, wraps a node component in React.memo comparing
only the props these components read:
and each of the 21 node components exports through it:
Comparing data by identity works because setDataPropsForNode replaces it
with a copy (store.tsx:1100). The helper's docstring notes the constraint: a
node component that starts reading
selectedordragginghas to comparethem here too.
Numbers
Two production builds served side by side and profiled in one browser
session (Chrome CPU profile over CDP), dragging a node for ~2.5s, two runs
each, M-series Mac. Share of wall clock off-idle, and total off-idle CPU:
The prompt node went from ~23 ms of CPU per frame to ~9 ms, so a drag that
could not hold 60fps now fits in the frame budget. Each node type pays this
cost when it is the one being dragged, which is why the table node gains as
much as the prompt node.
Checked
prettier -c, eslint, tsc --noEmit and craco test (68 suites, 1234 tests) pass.