Performance
General rules
Limit the number of Views and Primitives
Creation of views and primitive have a cost even if they are not shown. So in general, avoid creation of element that are not necessary.
Create View for multiple children
When you want to mutualize behavior or style of a Primitive
, for example create Title
that will always have the same style, it is better to create a custom Primitive
rather than a custom View
. Generated hierarchy will be better for renderer.
BAD
export default $Screen.declare("MyScreen", {
children: {
title: {
class: $LabelAtomView,
text: "A title"
}
}
});
export default $View.declare("LabelAtomView", {
properties: /** @lends LabelAtomView.prototype */ {
size: ({theme}) => theme.fontSize.H1.size,
family: ({theme}) => theme.fontFamily.REGULAR,
color: ({theme}) => theme.color.LIGHT,
ellipsis: true
},
children: {
label: {
class: $TextPrimitive,
text: ({parent}) => parent.text,
size: ({parent}) => parent.size,
family: ({parent}) => parent.family,
color: ({parent}) => parent.color,
ellipsis: ({parent}) => parent.ellipsis
}
}
});
Generated hierarchy will be like
- MyScreen
- LabelAtomView
- TextPrimitive
GOOD
export default $Screen.declare("MyScreen", {
children: {
title: {
class: $LabelAtomPrimitive,
text: "A title",
}
}
});
export default $TextPrimitive.declare("LabelAtomPrimitive", {
properties: /** @lends LabelAtomPrimitive.prototype */ {
size: ({theme}) => theme.fontSize.H1.size,
family: ({theme}) => theme.fontFamily.REGULAR,
color: ({theme}) => theme.color.LIGHT,
ellipsis: true
}
});
Generated hierarchy will be like :
- MyScreen
- LabelAtomPrimitive
Only create children that is used
We often see that for tile in rail that could have a children visible depending on something. It is better to have 2 different views rather than one that do both jobs.
Example:
We create a screen with 2 tiles: one poster and one landscape. They should look like the same, only on landscape we should display a text whereas on poster there is no text.
BAD
export default $Screen.declare("MyScreen", {
children: {
posterTile: {
class: $TileView,
layout: "POSTER",
data: {
src: "poster.jpg"
}
},
landscapeTile: {
class: $TileView,
layout: "LANDSCAPE",
data: {
src: "landscape.jpg",
title: "My landscape",
}
}
}
});
export default $View.declare("TileView", {
children: {
image: {
class: $ImagePrimitive,
src: ({parent}) => parent.data.src
},
label: {
class: $TextPrimitive,
text: ({parent}) => parent.data.title
}
},
properties: /** @lends TileView.prototype */ {
layout: "POSTER" // Or could be "LANDSCAPE"
},
style: {
label: {
opacity: ({parent}) => parent.layout === "POSTER": 0 ? 1
}
}
});
GOOD
Note
We use inheritance to mutualize image behavior between TileView and LandscapeTileView.
export default $Screen.declare("MyScreen", {
children: {
posterTile: {
class: $TileView,
data: {
src: "poster.jpg"
}
},
landscapeTile: {
class: $LandscapeTileView,
data: {
src: "landscape.jpg",
title: "My landscape"
}
}
}
});
export default $View.declare("TileView", {
children: {
image: {
class: $ImagePrimitive,
src: ({parent}) => parent.data.src
}
}
});
export default $TileView.declare("LandscapeTileView", {
children: {
label: {
class: $TextPrimitive,
text: ({parent}) => parent.data.title
}
}
});
Limit the number of binding
Each time you are using arrow function in properties or style, you put in place binding mechanism. Binding has a cost, so for better performance you need to be careful to use binding when you need it.
Use Theme statics as long as you do not need theme variables to be hot reloaded
BAD
export default $AbstractTheme.declare("AppTheme", {
properties: {
FONT_REGULAR: "MyFontRegular",
FONT_BOLD: "MyFontBold"
}
});
export default $TextPrimitive.declare("LabelAtomPrimitive", {
properties: /** @lends LabelAtomPrimitive.prototype */ {
family: ({theme}) => theme.FONT_REGULAR
}
});
GOOD
export default $AbstractTheme.declare("AppTheme", {
statics: {
FONT_REGULAR: "MyFontRegular",
FONT_BOLD: "MyFontBold"
}
});
import $Theme from "@Theme";
export default $TextPrimitive.declare("LabelAtomPrimitive", {
properties: /** @lends LabelAtomPrimitive.prototype */ {
family: $Theme.FONT_REGULAR
}
});
Caution
Known limitation about statics declaration: you can not declare object.
statics: {
COLORS: {
RED: "#FF0000",
GREEN: "#00FF00",
BLUE: "#0000FF"
}
}
Only one level is authorized.
statics: {
COLORS_RED: "#FF0000",
COLORS_GREEN: "#00FF00",
COLORS_BLUE: "#0000FF"
}
Do not create useless properties
Example: here we create the property color
and bind it then to label.color
:
BAD
export default $View.declare("TileView", {
properties: {
color: "#000000"
},
children: {
label: {
class: $TextPrimitive
}
},
style: {
label: {
color: ({parent}) => parent.color
}
}
});
It is better to directly set the color in label.color
to avoid not usefull binding :
GOOD
export default $View.declare("TileView", {
children: {
label: {
class: $TextPrimitive
}
},
style: {
label: {
color: "#000000"
}
}
});
This is a very basic example, but it is the same if you have some condition in your property.