We should discourage usage of ready callback, and maybe... the upgrader should move code from ready() -> connectedCallback()
Why discourage the use of ready?
We should caution against the overuse of ready, perhaps (fort example, doing static config instead of responding to state change using observers, slotchange, etc.) ... But I think there's still a valid case for one-time initialization code.
I forgot to put it's related to Polymer 2.0
So, Polymer 2 is getting closer to native api... then it makes more sense using connectedCallback or constructor
OK... Just wondering if you had a particular reason for wanting to do away with ready.
It's true that Polymer 2.0 is getting closer to the native API... But connectedCallback can be called more than once, and in the constructor, you can't read attributes or manipulate DOM. Polymer needs something like ready in order to create shadow DOM and initialize the data system. So it probably makes sense to expose it to the user for other one-time initialization.
That said, I'd love to give people good guidance for avoiding overusing ready. I defer to @sorvell and @kevinpschaaf on whether we want to discourage use of it altogether, or provide more prescriptive advice on what to put in there.
No particular reason :)
It's just because I was upgrading my elements then I felt like ready code was not making sense anymore
I don't want to remove ready callback... this api is important... It's only about the guidance and for staying as close as possible to the native api (which poly 2.0 is doing really great by the way)
@arthurevans Your answer here is spot-on.
Re: better guidance, I think it's true that there is actually very little legitimate work a user should put in ready and not elsewhere. Perhaps the docs related to lifecycle callbacks could list some more specific examples of work appropriate for each callback (they already list general guidance):
constructorproperties: { prop: { value: ... } }this._boundHandleEvent = this._handleEvent.bind(this);, although somewhat obviated by ES6 => functions)Polymer.dom(this).observeNodes observer to watch for childrenconnectedCallback / disconnectedCallbackaddEventListener in constructor or defer to requestAnimationFrame)requestAnimatinoFrame to perform measurement based on rendered layout in DOMconnectedCallback should be balanced with associated teardown work in disconnectedCallback; if not it usually means connectedCallback is the wrong place to do it_connectedCallback, as they are not guaranteed to be parsed yet per the spec; instead, use the observeNodes helper to detect when children are added or distributed to this element._Polymer.dom(this).observeNodes called from constructorobserver / observersreadyAt this point it's hard to contrive _general_ a use case where ready is the only/best place to do work, although they do come up from time to time in very specific cases. That said, as Arthur mentioned Polymer still uses it internally and we just left it publicly overridable mostly for BC.
Alternately, maybe a list of things you might be _tempted_ to do in ready that should be done elsewhere would be valuable in the docs...?
ready anti-patterns:childrenPolymer.dom(this).observeNodes callback insteadchildren may not be parsed yet, since ready may be called from connectedCallback for top-level element. Also, observeNodes callback is called for _every_ change to the child nodes and changes to distributed nodes; performing one-time work means the element is not robust to children changes.observer insteadready is called only once, so work done here based on a property value may become invalidated if the property value is changed at a later point by the userrequestAnimationFrame enqueued from connectedCallback (if one-time) or an observer (if measurement depends on current property values)ready callback may be called before the browser's style system can return proper layout/computed style information; requestAnimationFrame is a safe place to perform measurement.constructor, 2.) connectedCallback/disconnectedCallback (if listener must be removed when out of document), or 3.) Polymer.RenderStatus.afterNextRender (for better performance if listener is not required for first paint)ready is likely not superior to constructor for this use case, and connectedCallback or afterNextRender are probably even better.@arthurevans @sorvell wdyt?
Thanks @kevinpschaaf I think that's super helpful.
Couple of questions:
observeNodes as opposed to slotchange? One of use cases I saw for ready was to observe the initial distribution, which isn't reported in slotchange. (Not immediately in ready, of course, but in a rAF or afterNextRender since as far as I know, you only need to do this once, and for obvious reasons it needs to happen after the shadow tree is created.)afterNextRender, I take that to mean aNR enqueued from either constructor or connectedCallback (depending on whether you need to remove and re-add the listener).rAF and aNR here if I'm understanding correctly is that at rAF time we expect layout to be done but not paint (earliest point you could expect measurements) and aNR should be after paint?Are we going to keep recommending observeNodes as opposed to slotchange?
As long as you have a shadowRoot and <slot>, for sure should use slotchange and not observeNodes
I take that to mean aNR enqueued from either constructor or connectedCallback
Correct.
and aNR should be after paint
Correct. afterNextRender is useful for deferring work that need not block paint (e.g. adding UI event listeners or aria attributes). requestAnimationFrame would be pre-paint.
Going ahead and closing since there's a lot of info here. Let me know if you have further questions.
Sorry to add to a closed issue... I have a question.
I am writing a decorator element, and I am doing:
connectedCallback () {
super.connectedCallback()
this._field = Polymer.FlattenedNodesObserver.getFlattenedNodes(this).find(el => el.nodeType === Node.ELEMENT_NODE)
if (!this._field) {
throw new Error('hot-realtime-field could not find the element to be decorated')
}
this._fieldIsCheckable = !!this._field._hasIronCheckedElementBehavior
this._listenToField()
}
Is this against best practices?
Since it's a decorator, it needs to discover its first child. However, this worries me:
Note: do not read children in connectedCallback, as they are not guaranteed to be parsed yet per the spec; instead, use the observeNodes helper to detect when children are added or distributed to this element.
I am obviously reading children... so, should I do this differently?
Most helpful comment
@arthurevans Your answer here is spot-on.
Re: better guidance, I think it's true that there is actually very little legitimate work a user should put in ready and not elsewhere. Perhaps the docs related to lifecycle callbacks could list some more specific examples of work appropriate for each callback (they already list general guidance):
Example callback work:
constructorproperties: { prop: { value: ... } }this._boundHandleEvent = this._handleEvent.bind(this);, although somewhat obviated by ES6=>functions)Polymer.dom(this).observeNodesobserver to watch for childrenconnectedCallback/disconnectedCallbackaddEventListenerinconstructoror defer torequestAnimationFrame)requestAnimatinoFrameto perform measurement based on rendered layout in DOMconnectedCallbackshould be balanced with associated teardown work indisconnectedCallback; if not it usually meansconnectedCallbackis the wrong place to do it_connectedCallback, as they are not guaranteed to be parsed yet per the spec; instead, use theobserveNodeshelper to detect when children are added or distributed to this element._Polymer.dom(this).observeNodescalled fromconstructorobserver/observersreadyAt this point it's hard to contrive _general_ a use case where
readyis the only/best place to do work, although they do come up from time to time in very specific cases. That said, as Arthur mentioned Polymer still uses it internally and we just left it publicly overridable mostly for BC.Alternately, maybe a list of things you might be _tempted_ to do in
readythat should be done elsewhere would be valuable in the docs...?List of
readyanti-patterns:childrenPolymer.dom(this).observeNodescallback insteadchildrenmay not be parsed yet, sincereadymay be called fromconnectedCallbackfor top-level element. Also,observeNodescallback is called for _every_ change to the child nodes and changes to distributed nodes; performing one-time work means the element is not robust to children changes.observerinsteadreadyis called only once, so work done here based on a property value may become invalidated if the property value is changed at a later point by the userrequestAnimationFrameenqueued fromconnectedCallback(if one-time) or anobserver(if measurement depends on current property values)readycallback may be called before the browser's style system can return proper layout/computed style information;requestAnimationFrameis a safe place to perform measurement.constructor, 2.)connectedCallback/disconnectedCallback(if listener must be removed when out of document), or 3.)Polymer.RenderStatus.afterNextRender(for better performance if listener is not required for first paint)readyis likely not superior toconstructorfor this use case, andconnectedCallbackorafterNextRenderare probably even better.@arthurevans @sorvell wdyt?