Skip to content

Instantly share code, notes, and snippets.

@andrejewski
Last active March 14, 2018 20:27
Show Gist options
  • Save andrejewski/ce3c2cb71af10b9c99bc1a0f535aa17e to your computer and use it in GitHub Desktop.
Save andrejewski/ce3c2cb71af10b9c99bc1a0f535aa17e to your computer and use it in GitHub Desktop.
Declaratively defer rendering for large components and lists (Can v2)
import Map from 'can/map/';
import Component from 'can/component/';
const viewModel = Map.extend('CanDeferVM', {
define: {
delayMs: {
value: 0,
set: x => parseInt(x, 10)
},
initialHtml: { value: null },
/*
This is a convenience prop for rendering lists in
chucks as one can pass (delay-scalar)="@index"
and the pieces will be loaded gradually.
*/
delayScalar: {
value: null,
set: x => parseInt(x, 10)
},
isActive: { value: false },
delay: {
get () {
const delayScalar = this.attr('delayScalar');
if (typeof delayScalar !== 'number') {
return this.attr('delayMs');
}
return delayScalar * this.attr('delayMs');
}
}
},
activate () {
const isActive = this.attr('isActive');
const isActivating = !!(this._timeout || this._request);
const shouldActivate = !(isActive || isActivating);
if (shouldActivate) {
this._timeout = setTimeout(() => {
this._request = requestAnimationFrame(() => {
this.attr('isActive', true);
this._timeout = null;
this._request = null;
});
}, this.attr('delay'));
}
},
cancel () {
if (this._timeout) {
clearTimeout(this._timeout);
this._timeout = null;
}
if (this._request) {
cancelAnimationFrame(this._request);
this._request = null;
}
}
});
export default Component.extend('CanDeferComponent', {
tag: 'can-defer',
viewModel,
template: '{{#if isActive}}<content/>{{else}}{{{initialHtml}}}{{/if}}',
leakScope: false,
events: {
inserted () {
this.viewModel.activate();
},
removed () {
this.viewModel.cancel();
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment