问题
That statement pasted in my question was copied from https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#Using_the_lifecycle_callbacks.
As a no-experience developer with Webcomponent, I am trying to understand all rule-of-thumbs and best practices recommended so far.
Continuing reading it says "... use Node.isConnected to make sure". It is quite obvious what it means: check if it is still connected but it is not clear, at least for me, what I should do to workaround it or what I should expect in some circustances.
My case is I am creating a Webcomponent to listen SSE (Server Sent Events). This will be usefull for a alife dashboard and several other scenarios. The SSE event will be basically responded either by NodeJs or Spring Webflux after consumed from Kafka Stream.
All simple examples I did so far I didn't face any issue with element not longer connected during connectedcallback.
Additionally, I didn't read any recommendation in Best Practices regard "element no longer connected".
I read few excellent discussions:
can-a-custom-elements-connectedcallback-be-called-more-than-once-before-disc
from where I learned that I can always trust in this lifecycle constructor --> connectedCallback --> disconnectedCallback.
And
How to have a 'connectedCallback' for when all child custom elements have been connected
where basically I learned there is not a specific method "called after all children were upgraded"
Both questions pass close to my question but it doesn't answer me: which challenge or risk should be aware of or how to workaround the possibility to "connectedCallback may be called once your element is no longer connected"? In my scenario described above is there any treatment I am missing? Should I created some observer that triggers when the element is not longer available to recreate an eventsource object and add again a Listener to such eventsource object?
I pasted the code bellow for ilustration and the complete Webcomponent example can be cloned from https://github.com/jimisdrpc/simplest-webcomponet and its backend from https://github.com/jimisdrpc/simplest-kafkaconsumer.
const template = document.createElement('template');
template.innerHTML = `<input id="inputKafka"/> `;
class InputKafka extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.attachShadow({mode: 'open'})
this.shadowRoot.appendChild(template.content.cloneNode(true))
const inputKafka = this.shadowRoot.getElementById('inputKafka');
var source = new EventSource('http://localhost:5000/kafka_sse');
source.addEventListener('sendMsgFromKafka', function(e) {
console.log('fromKafka');
inputKafka.value = e.data;
}, false);
}
attributeChangedCallback(name, oldVal, newVal) {
console.log('attributeChangedCallback');
}
disconnectedCallback() {
console.log('disconnectedCallback');
}
adoptedCallback() {
console.log('adoptedCallback');
}
}
window.customElements.define("input-kafka", InputKafka);
回答1:
The only case when connectedCallback()
is called after the Custom Element is disconnected is when you play with it: moving it or removing it very quickly after it is created could sometimes lead to this situation.
In your described use case, if you're using a persistent, single page application to host your Web Component, this will never happen. Actually your Custom Element will never be disconnected, until the page is closed.
回答2:
In addition to what @supersharp has said I will add one other thing:
Do not call attachShadow
in connectedCallback
:
Your code:
class InputKafka extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'})
this.shadowRoot.appendChild(template.content.cloneNode(true))
const inputKafka = this.shadowRoot.getElementById('inputKafka');
const source = new EventSource('http://localhost:5000/kafka_sse');
source.addEventListener('sendMsgFromKafka', function(e) {
console.log('fromKafka');
inputKafka.value = e.data;
}, false);
}
}
Your code should call attachShadow
in the constructor
class InputKafka extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'})
this.shadowRoot.appendChild(template.content.cloneNode(true))
const inputKafka = this.shadowRoot.getElementById('inputKafka');
const source = new EventSource('http://localhost:5000/kafka_sse');
source.addEventListener('sendMsgFromKafka', function(e) {
console.log('fromKafka');
inputKafka.value = e.data;
}, false);
}
}
Otherwise you will be attempting to create a new shadowRoot every time your component is attached to the body. Yes, your code may not do that, but always write your code assuming that someone will attach, remove and re-attach.
If you are not using shadowDOM then you will want to wait until connectedCallback
is called to add your child elements as specified in the Requirements for Custom Element Constructors.
I either create my child elements one time, if they are complex, or every time the component is connected, when a property changes or when an attribute changes.
来源:https://stackoverflow.com/questions/56857611/how-deal-connectedcallback-may-be-called-once-your-element-is-no-longer-connect