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.