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 aPrimitive
andStyle
that will be applied to it.Primitive
- an object that encapsulates the logic for creating, measuring, and setting properties on the mount content (aView
or 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 aView
or aDrawable
. For the latter, theDrawableAllocator
should 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 @PropDefault
s 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.