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
});
}