I have a simple composable function which contains LazyColumn:
@Composable
fun MyScreen(itemList: List<Item>) {
LazyColumn {
intems(itemList) {
...
}
}
}
Everything works great, but my ViewState(itemList
) should change when the scroll reaches some position index. That's why I add the following lines to my composable function:
@Composable
fun MyScreen(itemList: List<Item>) {
val lazyListState = rememberLazyListState()
viewModel.onPositionChanged(lazyListState.firstVisibleItemIndex)
LazyColumn(state = lazyListState) {
intems(itemList) {
...
}
}
}
Everything works as I expected, but performance has noticeably deteriorated. How I can fix it?
CodePudding user response:
You have two problems here:
- You're reading the state directly in the Composable with
lazyListState.firstVisibleItemIndex
, this causes continues recompositions - each time any part oflazyListState
changes, e.g. on each scrolled pixel. - You're making
viewModel.onPositionChanged
call directly from composable. It's recommended to make such calls from special side effect functions, read more about the topic in thinking in compose and side effects documentation.
In this case LaunchedEffect
with snapshotFlow
can be used like this:
LaunchedEffect(Unit) {
snapshotFlow { lazyListState.firstVisibleItemIndex }
.collect(viewModel::onPositionChanged)
}
You can also face same problem when you need to update the view depending on the list state. In such case derivedStateOf
should be used: it'll cause recomposition only when the calculated value actually changes.
val firstVisibleItemIndex by remember {
derivedStateOf {
lazyListState.firstVisibleItemIndex
}
}