Hey has anyone seen interesting behaviour where la...
# compose
n
Hey has anyone seen interesting behaviour where lazy lists (in our case lazy columns) recompose most of the visible items without the data changing? We are observing a calc based on the first index / first item offset to hide /show something which doesn’t look like its in the same compose scope as the list. When this value becomes stable it stops this recomposing behaviour. Theories in thread.
One theory is that it may have something to do with the “stability / immutability” of the data being passed to the items in the lazy column as I was unable to reproduce the issue with a really basic case. (Something along the path of compose unable to skip because it isn’t sure if the data is stable) Does this seem like a reasonable place to dig into?
Previously we have normally hoisted the composable that observes this value up and put it in a slot so that the offset calc is far away from the list itself however really want to understand whats going on.
i
Are you using the
key
parameter on
items
to denote what the stable and unique key is for each item? https://developer.android.com/reference/kotlin/androidx/compose/foundation/lazy/package-summary#(androidx.compose.founda[…]nction1,kotlin.Function2)
n
I was originally just wrapping it in key inside of the items function but have added a key lambda there instead. Still same behaviour. I meant to add a sample code snippet originally to make sure it wasn’t something obvious but accidentally dropped it off 🤦
Copy code
@Composable
fun AScreen() {
    val listState = rememberLazyListState()
    Column(
        Modifier
            .fillMaxSize()
    ) {
        Box(Modifier.fillMaxWidth()) {
            val offset by remember {
                derivedStateOf {
                    // custom calc function that works out offset based on first index etc
                    listState.scrollOffsetPercent(0.2f)
                }
            }

            Text(
                "some title",
                modifier = Modifier
                    .align(Alignment.Center)
                    .padding(horizontal = 64.dp),
                color = lerp(
                    Color.Transparent,
                    Color.Red,
                    offset
                ),
            )

        }
        Column(Modifier.padding(horizontal = 16.dp)) {
            LazyColumn(
                modifier = Modifier,
                state = listState,
                contentPadding = PaddingValues(bottom = 136.dp)
            ) {
                // items that recompose whilst offset isn't stable
            }

        }
    }
}
So as soon as offset is stable the visible values in the lazy column stop recomposing all the time and just recompose as expected when they are scrolled into view. Normally we could make the argument that we could ignore this however due to the items being non trivial the screen gets a bit laggy
To anyone that reads this later I hoisted the component that was observing the offset value up (something similar to code below). Still would very much prefer to solve the root issue if anyone does have any other ideas.
Copy code
@Composable
fun ScreenAParent() {
    val listState = rememberLazyListState()
    ScreenA(
        header = {
            val offset by remember {
                derivedStateOf {
 // custom calc function that works out offset based on first index etc
                    listState.scrollOffsetPercent(0.2f)
                }
            }

            ScreenAHeader(offset)
        },
        listState = listState
    )

}

@Composable
fun ScreenA(
    header: @Composable () -> Unit,
    listState: LazyListState
) {
    header()

    LazyColumn(
        modifier = Modifier,
        state = listState,
   ) {
        //items no longer recompose when offset changes
    }
}