You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a redraw is called and didRecycle is triggered on an element, if didRecycle subsequently makes changes and calls another redraw, the second redraw is ignored and changes aren't reflected until something else triggers another redraw.
Minimal example demonstrating issue: https://jsfiddle.net/2j3phtag/. Here you'll see that the recycle lags one behind the main counter, until the view is updated apart from the recycle hook.
The use-case we have is that when a node is recycled its required size may overflow the bounds of its container, in which case we activate scroller buttons. If we do so, we need to trigger another redraw with the buttons now visible. We expected that just calling redraw would be sufficient.
The text was updated successfully, but these errors were encountered:
I looked into this with Clay yesterday, and it seems to me that the drainQueue function is where the problem lies. Redraws during other hooks, and during render functions are also affected (for example, didRedraw, below).
function drainQueue() {
redrawQueue.forEach(vm => {
// don't redraw if vm was unmounted
if (vm.node == null)
return;
// don't redraw if an ancestor is also enqueued
var parVm = vm;
while (parVm = parVm.parent()) {
if (redrawQueue.has(parVm))
return;
}
vm.redraw(true);
});
didRedraws(redrawQueue);
redrawQueue.clear();
rafId = 0;
}
The forEach function is documented to not observe any elements added while the loop is iterating, so any redraws that would get queued while processing redraw hooks are immediately discarded by the redrawQueue.clear().
Instead the function should extract the array, clear the queue, and then requeue the drain call if the queue has new entries. Something like this (untested, off the cuff):
function drainQueue() {
let elms = redrawQueue.entries();
redrawQueue.clear();
elms.forEach([vm,_] => {
// don't redraw if vm was unmounted
if (vm.node == null)
return;
// don't redraw if an ancestor is also enqueued
var parVm = vm;
while (parVm = parVm.parent()) {
if (redrawQueue.has(parVm))
return;
}
vm.redraw(true);
});
didRedraws(elms);
rafId = 0;
if (redrawQueue.size() > 0)
requestAnimationFrame(drainQueue);
}
I can take care of this if you wish. May want to consider a counter to limit the number of cycles as a failsafe; after, say, 1000 redraws interrupt the cycle with a log message indicating so.
lawrence-dol
changed the title
Redraws called from a DidRecycle lifecycle are ignored.
Redraws called from a didRecycle hook are ignored.
Mar 23, 2023
When a redraw is called and
didRecycle
is triggered on an element, ifdidRecycle
subsequently makes changes and calls another redraw, the second redraw is ignored and changes aren't reflected until something else triggers another redraw.Minimal example demonstrating issue: https://jsfiddle.net/2j3phtag/. Here you'll see that the recycle lags one behind the main counter, until the view is updated apart from the recycle hook.
The use-case we have is that when a node is recycled its required size may overflow the bounds of its container, in which case we activate scroller buttons. If we do so, we need to trigger another redraw with the buttons now visible. We expected that just calling redraw would be sufficient.
The text was updated successfully, but these errors were encountered: