Vivek Modi
Vivek Modi

Reputation: 7281

Using Interfaces vs Lambda Functions in Jetpack Compose Composables

In Jetpack Compose, it's common to pass lambda functions as parameters in both stateful and stateless composables. I'm considering using interfaces for this purpose instead and would like to understand the implications of this approach.

  1. Is using interfaces instead of lambda functions in this context against Jetpack Compose guidelines or best practices?

  2. What are the potential drawbacks of using interfaces in place of lambda functions for passing callbacks or other functional parameters in Composables?

Simple example:interface

MyComposableCallback {
    fun onEventOccurred(data: String)
}

@Composable
fun MyComposable(callback: MyComposableCallback) {
    // Composable implementation
}

// Usage
val myCallback = object : MyComposableCallback {
    override fun onEventOccurred(data: String) {
        // Handle event
    }
}

MyComposable(callback = myCallback)

As opposed to the more conventional lambda approach:

@Composable
fun MyComposable(onEventOccurred: (String) -> Unit) {
    // Composable implementation
}

// Usage
MyComposable { data ->
    // Handle event
}

Any insights on the pros and cons of each approach in terms of performance, readability, and adherence to Compose principles would be greatly appreciated.

Upvotes: 2

Views: 747

Answers (1)

Emmanuel Montt
Emmanuel Montt

Reputation: 376

an interface could affect to recompositions because it's unstable

documentation said:

Compose considers a type stable only if it can prove it. For example, an interface is generally treated as not stable, and types with mutable public properties whose implementation could be immutable are not stable either.

If Compose is not able to infer that a type is stable, but you want to force Compose to treat it as stable, mark it with the @Stable annotation

Example

// Marking the type as stable to favor skipping and smart recompositions.
@Stable
interface UiState<T : Result<T>> {
    val value: T?
    val exception: Throwable?

    val hasError: Boolean
        get() = exception != null
}

Link -> https://developer.android.com/jetpack/compose/lifecycle

I recommend you better to use an Actions class in your composable.

Ejem

data class MyComposableCallbackActions(
        val onEventOccurred: (String) -> Unit
    )

@Composable
fun rememberMyComposableCallbackActions(
    viewmodel: ViewModel
): MyComposableCallbackActions =
    remember {
        MyComposableCallbackActions(
            onEventOccurred = viewmodel::onEventOccurred
        )
    }

@Composable
fun MyComposable(actions: MyComposableCallbackActions) {
    // Composable implementation
}

This allows us to introduce the same level and ease of grouping our Actions related to our Screen and a more simple way to pass these actions to the relevant components.

"remember" help you to avoid unnecessary UI re-rendering.

Link -> https://levinzon-roman.medium.com/jetpack-compose-ui-architecture-a34c4d3e4391

Upvotes: 2

Related Questions