From bd6cca12c3fbd4b3fedd1de74dc083a6b61c4346 Mon Sep 17 00:00:00 2001 From: ogaclejapan Date: Sun, 25 Aug 2024 09:19:35 +0900 Subject: [PATCH] Replace DerivedState with StateFlow The `derivedStateOf` defined in the Composable functions of the query-compose-runtime module has been replaced with `StateFlow`, which offers the same functionality. The StateFlow does not emit a value if it remains unchanged, ensuring that the behavior remains unaltered. - ErrorBoundary - Suspense --- .../query/compose/runtime/ErrorBoundary.kt | 23 +++++++++++------- .../soil/query/compose/runtime/Suspense.kt | 24 ++++++++++--------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/soil-query-compose-runtime/src/commonMain/kotlin/soil/query/compose/runtime/ErrorBoundary.kt b/soil-query-compose-runtime/src/commonMain/kotlin/soil/query/compose/runtime/ErrorBoundary.kt index fdeac3a..6aa5bed 100644 --- a/soil-query-compose-runtime/src/commonMain/kotlin/soil/query/compose/runtime/ErrorBoundary.kt +++ b/soil-query-compose-runtime/src/commonMain/kotlin/soil/query/compose/runtime/ErrorBoundary.kt @@ -9,12 +9,13 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable -import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow /** * Wrap an ErrorBoundary around other [Catch] composable functions to catch errors and render a fallback UI. @@ -71,7 +72,7 @@ fun ErrorBoundary( state: ErrorBoundaryState = remember { ErrorBoundaryState() }, content: @Composable () -> Unit ) { - val currentError by remember(state) { derivedStateOf { state.error } } + val currentError by state.error.collectAsState() val onErrorCallback by rememberUpdatedState(newValue = onError) val onResetCallback by rememberUpdatedState(newValue = onReset) Box(modifier) { @@ -115,13 +116,11 @@ class ErrorBoundaryContext( */ @Stable class ErrorBoundaryState : CatchThrowHost { - private val hostMap = mutableStateMapOf() + private val hostMap = mutableMapOf() - /** - * Returns the caught error. - */ - val error: Throwable? - get() = hostMap.values.firstOrNull() + // FIXME: This can be fixed by enabling K2 mode + private val _error = MutableStateFlow(null) + val error: StateFlow = _error override val keys: Set get() = hostMap.keys @@ -131,9 +130,15 @@ class ErrorBoundaryState : CatchThrowHost { override fun set(key: Any, error: Throwable) { hostMap[key] = error + onStateChanged() } override fun remove(key: Any) { hostMap.remove(key) + onStateChanged() + } + + private fun onStateChanged() { + _error.value = hostMap.values.firstOrNull() } } diff --git a/soil-query-compose-runtime/src/commonMain/kotlin/soil/query/compose/runtime/Suspense.kt b/soil-query-compose-runtime/src/commonMain/kotlin/soil/query/compose/runtime/Suspense.kt index 4322d84..b384fa9 100644 --- a/soil-query-compose-runtime/src/commonMain/kotlin/soil/query/compose/runtime/Suspense.kt +++ b/soil-query-compose-runtime/src/commonMain/kotlin/soil/query/compose/runtime/Suspense.kt @@ -9,14 +9,15 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable -import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds @@ -55,9 +56,7 @@ fun Suspense( contentThreshold: Duration = 3.seconds, content: @Composable () -> Unit ) { - val isAwaited by remember(state) { - derivedStateOf { state.isAwaited() } - } + val isAwaited by state.isAwaited.collectAsState() var isFirstTime by remember { mutableStateOf(true) } Box(modifier = modifier) { CompositionLocalProvider(LocalAwaitHost provides state) { @@ -80,7 +79,11 @@ fun Suspense( */ @Stable class SuspenseState : AwaitHost { - private val hostMap = mutableStateMapOf() + private val hostMap = mutableMapOf() + + // FIXME: This can be fixed by enabling K2 mode + private val _isAwaited = MutableStateFlow(false) + val isAwaited: StateFlow = _isAwaited override val keys: Set get() = hostMap.keys @@ -90,16 +93,15 @@ class SuspenseState : AwaitHost { override fun set(key: Any, isAwaited: Boolean) { hostMap[key] = isAwaited + onStateChanged() } override fun remove(key: Any) { hostMap.remove(key) + onStateChanged() } - /** - * Returns `true` if any of the [Await] is awaited. - */ - fun isAwaited(): Boolean { - return hostMap.any { it.value } + private fun onStateChanged() { + _isAwaited.value = hostMap.any { it.value } } }