Skip to content

[UX Live Component] Bug: Stale ValueStore after component reconnect (disconnect → connect without initialize) #3424

@Pechynho

Description

@Pechynho

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions