Migrating MountSpecs
This page outlines the process of migrating from MountSpecs to Primitive Components.
Unlike MountSpecs, Primitive Components consist of two separate pieces:
PrimitiveComponent.render()- a method that returns aPrimitiveandStylethat will be applied to it.Primitive- an object that encapsulates the logic for creating, measuring, and setting properties on the mount content (aViewor aDrawable).
The following two sections contain information on how to migrate MountSpec static lifecycle methods into a Primitive Component render() and the Primitive it returns. The Cheatsheet can also be consulted for a set of links for the migration of individual aspects of existing code.
Setup - Adding Dependenciesβ
To use the Kotlin Litho API you'll need to add the following dependencies into your BUCK file:
deps = [
"//fbandroid/libraries/components/litho-core/src/main/java/com/facebook/litho:litho",
"//fbandroid/libraries/components/litho-widget-kotlin/src/main/kotlin/com/facebook/litho/kotlin/widget:widget", # for widgets
],
More details on the setup steps are outlined in the Introduction and Setup page.
Exampleβ
The below example shows a comparison of a simple component implemented with MountSpec and Primitive Component API.
| MountSpec | PrimitiveComponent |
|---|---|
| |
The Primitive Component API is composable, its most important building blocks are:
ViewAllocator- responsible for creating the content it hosts. Content can be aViewor aDrawable. For the latter, theDrawableAllocatorshould be used.LayoutBehavior- responsible for measuring and determining the final size of theComponent.MountBehavior- responsible for setting and unsetting properties on the content.
For more information about Primitive Component API refer to the documentation.
Migrating MountSpec to PrimitiveComponentβ
Creating componentsβ
In the MountSpec API the component spec class serves as a description which is used by the annotation processor to generate the actual component at compile time. In the Primitive Component API the component is a regular class and annotation processing is no longer needed. To get more details you can read Creating a Primitive Component page.
| MountSpec | PrimitiveComponent |
|---|---|
| |
Passing propsβ
In Spec API for every method parameter annotated with @Prop annotation, a builder method is generated for setting a value of that property when instantiating the component. In Kotlin API props are passed as constructor parameters, and @PropDefaults are replaced by default values of these parameters.
| MountSpec | PrimitiveComponent |
|---|---|
| |
Common propsβ
In Spec API common props such as margin, clickHandler, alpha could be applied to any Ρomponent using its generated builder methods. In Primitive Component API similar to other Kotlin API components, if a component wants to accept common props they should be passed via Style prop.
| MountSpec | PrimitiveComponent |
|---|---|
| |
Creating mountable contentβ
In MountSpec API content creation is configured in the method annotated with @OnCreateMountContent annotation by returning a proper View or Drawable instance. In Primitive Components API it is implemented by creating a ViewAllocator or a DrawableAllocator and passing it to MountBehavior.
More information on Primitive content creation can be found on the dedicated Lifecycle of a Primitive Component page.
| MountSpec | PrimitiveComponent |
|---|---|
| |
Measurementβ
@OnMeasureβ
Measuring a component using MountSpec API is done by implementing a method annotated with @OnMeasure annotation. The size of a component is returned by setting width and height values on the Size input parameter. In Primitive Component API the measurement logic is defined in an implementation of LayoutBehavior interface. The size of a component is returned in PrimitiveLayoutResult.
More information on Primitive Component content measurement can be found here.
| MountSpec | PrimitiveComponent |
|---|---|
| |
@OnBoundsDefinedβ
The method annotated with @OnBoundsDefined annotation can receive outputs from method annotated with @OnMeasure annotation and is executed after layout calculation. It can be used to perform additional operations after final size of the Component is known, but before the Component is mounted. In Primitive Component API the logic needs to be merged into a single layout() method.
| MountSpec | PrimitiveComponent |
|---|---|
| |
For most common measurement use cases, there are a few built-in LayoutBehavior implementations available.
Mounting contentβ
@OnMount/@OnUnmount and @ShouldUpdateβ
In MountSpec API the properties can be set and unset on the content in methods annotated with @OnMount and @OnUnmount. Additionally a method annotated with @ShouldUpdate can be added to tell the framework when the content should be re-mounted - if @ShouldUpdate method returns true, then @OnUnmount method will be invoked, followed by @OnMount method. In Primitive Components, the bind(deps){} API should be used. The deps parameter is used as a replacement of @ShouldUpdate method - the deps are automatically checked to determine if re-mount should happen.
More information on mounting content with Primitive Component API can be found here.
| MountSpec | PrimitiveComponent |
|---|---|
| |
@OnBind/@OnUnbindβ
The @OnBind and @OnUnbind are similar to @OnMount and @OnUnmount, the only difference is that @OnBind and @OnUnbind are called on each update, regardless of the value returned from @ShouldUpdate annotated method. In Primitive Components API @OnBind and @OnUnbind can be replaced with bind(Any()){}. Using Any() as deps will ensure that the content will be re-mounted every time.
| MountSpec | PrimitiveComponent |
|---|---|
| |
@OnBindDynamicValueβ
Dynamic props are properties that are applied directly to a View or Drawable without triggering a new layout or mount. In MountSpec API the dynamic value is set on a content by annotating a method with @OnBindDynamicValue annotation. In PrimitiveComponents API bindDynamic API should be used.
| MountSpec | PrimitiveComponent |
|---|---|
| |
Pre-allocationβ
In MountSpec API pre-allocation is configured by providing the parameters to @MountSpec annotation. In Primitive Component API the pre-allocation is configured via ViewAllocator/DrawableAllocator.
More information on Primitive Component pre-allocation can be found here.
| MountSpec | PrimitiveComponent |
|---|---|
| |
Pre-filling content poolβ
Content can be manually pre-filled ahead of time using one of the methods from MountContentPools, such as prefillMountContentPool. For MountSpec API the Component instance should be passed as the ContentAllocator parameter. In Primitive Components API a ViewAllocator/DrawableAllocator should be passed instead. In order to do that, the allocator can be defined inside of a companion object which will allow for accessing it without creating an instance of the Component.
More information on pre-filling content pools with Primitive Component API can be found here.
| MountSpec | PrimitiveComponent |
|---|---|
| |
hasChildLithoViewsβ
Configuring hasChildLithoViews in MountSpec API is done by passing the boolean value to @MountSpec's parameter. In Primitive Components API there is a doesMountRenderTreeHosts flag available inside of MountConfigurationScope.
| MountSpec | PrimitiveComponent |
|---|---|
| |
@ShouldExcludeFromIncrementalMountβ
Excluding a Component from Incremental Mount in MountSpec API is done by creating a method annotated with @ShouldExcludeFromIncrementalMount annotation. If such method returns true, then the Component will be excluded from Incremental Mount. In Primitive Components API there is a shouldExcludeFromIncrementalMount flag available inside of MountConfigurationScope.
| MountSpec | PrimitiveComponent |
|---|---|
| |
Othersβ
isPureRenderβ
In Primitive Component API there is no equivalent of @MountSpec(isPureRender = true). All Primitive Components are pure render. When migrating from MountSpec to Primitive Component, the isPureRender parameter should be ignored.
@OnPrepare and@OnLoadStyleβ
In Primitive Component API there is no equivalent of @OnPrepare and @OnLoadStyle. When migrating from MountSpec to Primitive Component, the @OnPrepare and @OnLoadStyle logic should be placed in Primitive Component's render() method.