-
-
Notifications
You must be signed in to change notification settings - Fork 413
[UX Live Component] Bug: Stale ValueStore after component reconnect (disconnect → connect without initialize) #3424
Description
Symfony version(s) affected
2.34.0
Description
When a live component is disconnected and later reconnected to the same DOM element (Stimulus reuses the controller instance), the ValueStore retains stale state from the previous component
lifecycle. This causes Invalid model name errors because the ValueStore props no longer match the server-rendered HTML.
The root cause: Stimulus calls initialize() only once per controller instance. On reconnect, only connect() is called — but connect() does not call createComponent(), so the old
Component (and its ValueStore) is reused with outdated props.
How to reproduce
Step 1 — Initial render
Stimulus calls initialize() → createComponent() → connect() on #child_component.
ValueStore is initialized with props containing form name abc.
<div id="parent_component" data-controller="live">
<div id="child_component" data-controller="live">
<form name="abc"></form>
</div>
</div>Step 2 — Parent action removes child component (div is reused)
Stimulus calls disconnect() on #child_component. The controller instance is kept alive by Stimulus (tied to the DOM element reference).
<div id="parent_component" data-controller="live">
<div">new content without live controller</div>
</div>Step 3 — Parent action re-adds child component (div is reused, form name changed)
Stimulus calls connect() (NOT initialize()) on #child_component — the previous controller instance is reused. createComponent() is never called, so the old Component with old ValueStore remains
active.
<div id="parent_component" data-controller="live">
<div id="child_component" data-controller="live">
<form name="xyz"></form>
</div>
</div>Expected behavior
The ValueStore should reflect the current server-rendered props (form name="xyz"). User input should work without errors.
Actual behavior
The ValueStore still holds props from step 1 (form name="abc"). When the user types into an input field, Component.set() is called with the new model name (based on xyz), but ValueStore.has()
returns false because it only knows about abc:
Uncaught Error: Invalid model name "xyz.content".
at Component.set (live_controller.js:1926:1)
at extended.updateModelFromElementEvent (live_controller.js:3131:1)
at extended.handleInputEvent (live_controller.js:3045:1)
Possible Solution
In the live controller's connect() method, detect when props have changed since the Component was created, and recreate it:
connect() {
const currentProps = this.propsValue;
const storedProps = this.component.valueStore.getOriginalProps();
if (JSON.stringify(currentProps) !== JSON.stringify(storedProps)) {
this.createComponent();
}
this.connectComponent();
this.mutationObserver.observe(this.element, { attributes: true });
}Additional Context
No response