ux
ux copied to clipboard
[LiveComponent] getComponent is undefined if the controller loads very quickly as explained in the docs
Based on the docs the getComponent
method should be called during initialize
. Becase it's a Promise
the method initialize
should be async
.
When the component loads very quickly, this.component
will be undefined in connect
:
import { Controller } from '@hotwired/stimulus';
import { getComponent } from '@symfony/ux-live-component';
export default class extends Controller {
async initialize() {
this.component = await getComponent(this.element);
}
connect() {
console.log(this.component); // undefined
}
}
Adding async connect
won't solve the problem. Adding a small delay will solve the problem. Another way is to call getComponent
inside async connect
. Either way, the documentation is a bit "obscure" about this and devs without a good JavaScript understanding will have the same issue.
I don't know if this is a bug or the way Stimulus work, but I was expecting that connect
will be called after initialize
resolve.
Any update or workaround? Still in the official documentation...
Instead of using connect there, you should rely on the events dispatched by the LiveComponent
What do you mean @smnandre ? It's the official example in Symfony docs!
The documentation is see
// assets/controllers/some-custom-controller.js
// ...
import { getComponent } from '@symfony/ux-live-component';
export default class extends Controller {
async initialize() {
this.component = await getComponent(this.element);
this.component.on('render:finished', (component) => {
// do something after the component re-renders
});
}
}
And it's a bit... skinny. What if I need component.emit based on some javascript event? Where would you put that logic?
onPaste() {
this.component.emitSelf("paste", { value });
}
Inside onPaste
, happens somtime that this.component is undefined, based on how fast the controller loads.
async initialize() {
this.component = await getComponent(this.element);
// THERE
this.component.on('render:finished', (component) => {
// do something after the component re-renders
});
}