Elye
Elye

Reputation: 60311

Jetpack Compose deriveStateOf side effect cannot work along snapshotFlow side effect?

When I have the below code, all works (i.e. When scrolling past the first row, a button appears. When scrolling past the second row, another button appears)

@ExperimentalAnimationApi
@Composable
fun TestSnapshotFlow() {
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        val listState = rememberLazyListState()

        LazyColumn(state = listState) {
            items(1000) { index ->
                Text(text = "Item: $index")
            }
        }

        var showButtonSnapshot by remember {
            mutableStateOf(false)
        }

        val showButtonDerive by remember(listState.firstVisibleItemIndex) {
            mutableStateOf(
                listState.firstVisibleItemIndex > 0
            )
        }

        Log.d("Track", "Recompose")
        Column {
            AnimatedVisibility(showButtonDerive) {
                Button({}) {
                    Text("Row 1 hiding")
                }
            }
            AnimatedVisibility(showButtonSnapshot) {
                Button({}) {
                    Text("Row 1 and 2 hiding")
                }
            }
        }

        LaunchedEffect(listState) {
            snapshotFlow { listState.firstVisibleItemIndex }
                .map { index -> index > 2 }
                .distinctUntilChanged()
                .collect {
                    Log.d("Track", "B $it")
                    showButtonSnapshot = it
                }
        }
    }
}

However, If I change

val showButtonDerive by remember(listState.firstVisibleItemIndex) {
    mutableStateOf(
        listState.firstVisibleItemIndex > 0
    )
}

to the DeriveStateOf

val showButtonDerive by remember {
    derivedStateOf {
        listState.firstVisibleItemIndex > 0
    }
}

It doesn't work as expected anymore. The second button won't appear. (even though I check that the collect did trigger and and change showButtonSnapshot to true, the recomposition didn't happen anymore).

Looks like deriveStateOf and snapshotFlow can't work together to trigger the recompose. Separate them out individually works.

Just for easier copy-&-paste to test, the full code that doesn't work as expected as below

@ExperimentalAnimationApi
@Composable
fun TestSnapshotFlow() {
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        val listState = rememberLazyListState()

        LazyColumn(state = listState) {
            items(1000) { index ->
                Text(text = "Item: $index")
            }
        }

        var showButtonSnapshot by remember {
            mutableStateOf(false)
        }

        val showButtonDerive by remember {
            derivedStateOf {
                listState.firstVisibleItemIndex > 0
            }
        }

        Log.d("Track", "Recompose")
        Column {
            AnimatedVisibility(showButtonDerive) {
                Button({}) {
                    Text("Row 1 hiding")
                }
            }
            AnimatedVisibility(showButtonSnapshot) {
                Button({}) {
                    Text("Row 1 and 2 hiding")
                }
            }
        }

        LaunchedEffect(listState) {
            snapshotFlow { listState.firstVisibleItemIndex }
                .map { index -> index > 2 }
                .distinctUntilChanged()
                .collect {
                    Log.d("Track", "B $it")
                    showButtonSnapshot = it
                }
        }
    }
}

Upvotes: 1

Views: 1166

Answers (1)

Phil Dukhov
Phil Dukhov

Reputation: 88297

It looks like you're doing everything right, and recomposition isn't triggered when it should. I suggest you report it.

As a tmp solution you can update the value from an other coroutine scope, for example from MainScope():

snapshotFlow { listState.firstVisibleItemIndex }
    .map { index -> index > 2 }
    .distinctUntilChanged()
    .collect {
        MainScope().launch {
            showButtonSnapshot = it
        }
    }

Upvotes: 1

Related Questions