Skip to content

Commit

Permalink
Merge pull request #77 from soil-kt/remove-derived-state
Browse files Browse the repository at this point in the history
Replace DerivedState with StateFlow
  • Loading branch information
ogaclejapan authored Aug 25, 2024
2 parents efa18ed + bd6cca1 commit 534edb2
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -115,13 +116,11 @@ class ErrorBoundaryContext(
*/
@Stable
class ErrorBoundaryState : CatchThrowHost {
private val hostMap = mutableStateMapOf<Any, Throwable>()
private val hostMap = mutableMapOf<Any, Throwable>()

/**
* Returns the caught error.
*/
val error: Throwable?
get() = hostMap.values.firstOrNull()
// FIXME: This can be fixed by enabling K2 mode
private val _error = MutableStateFlow<Throwable?>(null)
val error: StateFlow<Throwable?> = _error

override val keys: Set<Any> get() = hostMap.keys

Expand All @@ -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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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) {
Expand All @@ -80,7 +79,11 @@ fun Suspense(
*/
@Stable
class SuspenseState : AwaitHost {
private val hostMap = mutableStateMapOf<Any, Boolean>()
private val hostMap = mutableMapOf<Any, Boolean>()

// FIXME: This can be fixed by enabling K2 mode
private val _isAwaited = MutableStateFlow(false)
val isAwaited: StateFlow<Boolean> = _isAwaited

override val keys: Set<Any> get() = hostMap.keys

Expand All @@ -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 }
}
}

0 comments on commit 534edb2

Please sign in to comment.