Only remount parent-passed components when their identity changed#3881
Only remount parent-passed components when their identity changed#3881T4rk1n wants to merge 3 commits into
Conversation
Since #3570, every component passed down from a parent whose children were updated by a callback got a bumped render key, forcing React to unmount and remount the entire subtree on every callback run - even when the returned children were the same components with only new prop values. This reset descendant state and made large subtree updates 3-4x slower (#3846). The forced remount is now conditional: the render key is only bumped when the component identity (namespace, type, id) at that path actually changed. The same component reconciles in place as before 4.2.0, while a different component at the same path still remounts, and stale descendant layout hashes are still reset - keeping #3330 fixed. The one reverted semantic from #3570 is that returning the same component (same type and id) from a callback no longer resets its internal state; return it with a different id to force a remount. Fixes #3846 Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
I believe that this resets to the initial behaviour of 4.1, this may be better served with a dash update type? For example, if the dev wants to reset the component via a callback, they just tell the callback to do so, which this forces its way down the tree? The default could be to not force remount. |
|
I took this for a spin and ran the example apps that PR 3570 fixed, and they both worked correctly. This looks good to me! @BSd3v are there any other use-cases to test? |
|
It's really just reimplementing a previous workaround and expanding the workaround features. This expands the use of arbitrary ids and can muddy up the DOM tree when unnecessary. The main thing is that the dev wants to be able to reset the children-type to an initial state, while this workaround obviously works (as it had prior in 4.1) I feel that a more robust definitive property makes more sense. Instead of placing in the documents that in order to remount you need to change the id that contains the information or change what the component is, rather than the ability to pass something to the Output of a callback and force it. |
|
Here's an example reported on the forum, that worked with pr 3570, but does not work on this branch: |
I implemented a fix for the component as props rendering, which seems to be the root cause of issues. |
|
I think the issue I have with this is that this just merges the component updates from the callback to the underlying components rather than resetting the children to their initially rendered state. There are several components that do this, AG Grid, dmc.Select to name a few. These components keep states within themselves that listen to updates. I believe that a more robust and dev controlled way to handle would be keep the mechanism created here to handle normal cases, but allow for the dev to specifically reset a component to its initial state based upon kwargs passed to the output. From an intuition perspective, it makes more sense for the component to reset from a callback the information that I am providing in a callback as the truth of what should be rendered, unless specifically patched. |
Keeps in-place reconcile as the default and adds an opt-in wrapper for callback returns that need a hard reset. remount() sets a private top-level marker (emitted by to_plotly_json, not a prop) that the renderer reads to bump the render key, unmounting the existing instance and mounting a fresh one instead of reconciling in place. This resets a stateful component's internal state without changing its id.
|
Resetting all the components all the time ends up being too expensive for the most simple cases as reported in #3846. I've added |
|
|
To force a remount on a component in the clientside it would be: |
Yes I confirm that works. |



Since #3570, every component passed down from a parent whose children were updated by a callback got a bumped render key, forcing React to unmount and remount the entire subtree on every callback run - even when the returned children were the same components with only new prop values. This reset descendant state and made large subtree updates 3-4x slower (#3846).
The forced remount is now conditional: the render key is only bumped when the component identity (namespace, type, id) at that path actually changed. The same component reconciles in place as before 4.2.0, while a different component at the same path still remounts, and stale descendant layout hashes are still reset - keeping #3330 fixed.
The one reverted semantic from #3570 is that returning the same component (same type and id) from a callback no longer resets its internal state; return it with a different id to force a remount.
Fixes #3846