You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extend Patch append perf fix to nested and non-tail locations
The O(appended) append fast-path only recognized appends at the top level
of a patched property, so a nested `p[0]['props']['children'].extend(...)`
fell back to the O(total-children) re-hydrate + path-table rebuild on every
click - the exact slowdown the top-level fix removed (reported in review of
#3948). Appending 250 nodes into a growing nested container went from a flat
~0.2s back up to ~8.6s at 3000 children.
- patchAnalysis: `tailAppends` now records `{location, count}` instead of a
bare count, so an append to a single nested list stays eligible. Appends to
two different lists, or any reorder/insert/delete, still disqualify it.
- executedCallbacks: the incremental path-table update targets
`oldChildrenPath + location` and slices the nested array. Gated to the plain
property value (not a dotted `figure.data` sub-path).
- DashWrapper: the item-by-item ref-skip now runs during a fresh, non-remount
render too, not only a settled reconcile. An ancestor rebuilt by assocPath on
the path down to a deep append still lets its `concat`-preserved children
reconcile in place instead of re-hydrating the whole list. A real remount
(identity change / dash.remount) still rebuilds everything. This half is
operation-agnostic, so a nested scalar Assign/arithmetic/Merge into a large
container is now O(1) re-hydration too, at parity with append.
Index-shifting ops (Prepend/Insert-mid/Delete/Remove/Reverse) remain
O(shifted) by nature - they genuinely move pre-existing items.
Tests: nested tail-append detection + multi-list/nested-disruption disqualify
cases in patch.test.js; nested-location appendPaths<->computePaths equivalence
in paths.test.js. Renderer unit 55/55; integration test_patch,
test_clientside_patch, test_redraw, test_children_reorder green.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,7 +20,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
20
20
- Fix components rendered as props (eg. component labels in `dcc.Dropdown` options, `dcc.Tab` labels) crashing with "can't access property 'props', layout is undefined" or failing to update when the host component's subtree was replaced by a callback. Components inserted out of the layout tree via `ExternalWrapper` now re-insert themselves when their layout entry was removed, so they update in place instead of updating a stale path.
21
21
- [#3929](https://github.com/plotly/dash/issues/3929) Fix components that set their own initial state on mount (eg. `dash-bootstrap-components` `Tabs`, which selects its default active tab) not applying that state on first render - a component's descendant layout hashes were reset on its very first fresh render, discarding the mount-time update before it took effect. The reset now only runs from the second fresh render onward, so a component's initial state survives (regression introduced in 4.2.0 by [#3570](https://github.com/plotly/dash/pull/3570)).
22
22
- [#3938](https://github.com/plotly/dash/pull/3938) Fix `dcc.Patch()` re-running the initial callbacks of components that were already on the page, including every matching (`MATCH`/`ALL`) element, and wiping their user-edited persisted values. Fixes [#3681](https://github.com/plotly/dash/issues/3681) and [#3937](https://github.com/plotly/dash/issues/3937)
23
-
- Fix `dcc.Patch().append()` (and `.extend()`) into a growing container getting progressively slower as the container fills — each append re-hydrated the entire children array (re-running `Registry.resolve` and prop hydration for every pre-existing child) and rebuilt the whole id→path table, making a single append cost O(total children) instead of O(appended). Appending 250 nodes to a 2750-node container dropped from ~4.5s back to a flat ~85ms, matching pre-4.2.0 behavior. Children that are the same object reference as the previous render now skip re-hydration (only for a settled component reconciling in place, never a first render or a forced remount), and pure tail-appends update the path table incrementally. Any change that reorders, inserts, replaces or writes a child still re-renders it normally.
23
+
- Fix `dcc.Patch().append()` (and `.extend()`) into a growing container getting progressively slower as the container fills — each append re-hydrated the entire children array (re-running `Registry.resolve` and prop hydration for every pre-existing child) and rebuilt the whole id→path table, making a single append cost O(total children) instead of O(appended). Appending 250 nodes to a 3000-node container dropped from ~8.6s back to a flat ~0.2s, matching pre-4.2.0 behavior. This now also covers appending to a *nested* list (eg. `p[0]['props']['children'].extend(...)`), which previously fell back to the full re-hydrate. Children that are the same object reference as the previous render skip re-hydration (unless the component is being remounted), and pure tail-appends — at any depth — update the path table incrementally. Any change that reorders, inserts, replaces or writes a child still re-renders it normally.
0 commit comments