Skip to content

Commit c053a68

Browse files
committed
Added derivedValue and rememberOnViewModel
1 parent e7e23c3 commit c053a68

File tree

5 files changed

+45
-2
lines changed

5 files changed

+45
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* Added reactive dependency injection solution (see `DI`) with graph tracking that can even re-create ViewModels when a DI module/node is changed at runtime.
66
* Added `ContextualVal`/`ContextualValSuspend` for coroutine-local variables (like thread-locals or `CompositionLocal` for coroutines).
77
* Made the experimental `ReactiveViewModel` more flexible by building it around `ContextualVal`.
8+
* Added Composable `rememberOnViewModel { ... }` which remembers the block's result across configuration changes.
9+
* Added Composable `DI.derivedState { ... }` and `DI.derivedValue { ... }` which remember the block's result until a dependency changes and re-render the UI when needed.
810
* Changed `loading` and all `withLoading` parameters from `MutableValueFlow` to `MutableStateFlow`.
911
* Changed `increment()`/`decrement()` and `replace` to work on `MutableStateFlow` instead of `MutableValueFlow`.
1012
* Added `MutableStateFlow.replaceAndGet` and `getAndReplace` which are like their similarly named `updateAndGet`/`getAndUpdate` counterparts, but with the value passed as `this`.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.ensody.reactivestate.compose
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.State
5+
import androidx.compose.runtime.collectAsState
6+
import com.ensody.reactivestate.DIImpl
7+
import com.ensody.reactivestate.DIResolver
8+
import com.ensody.reactivestate.ExperimentalReactiveStateApi
9+
10+
@ExperimentalReactiveStateApi
11+
@Composable
12+
public inline fun <reified T> DIImpl.derivedValue(key: Any? = null, crossinline block: DIResolver.() -> T): T =
13+
derivedState(key = key) { block() }.value
14+
15+
@ExperimentalReactiveStateApi
16+
@Composable
17+
public inline fun <reified T> DIImpl.derivedState(key: Any? = null, crossinline block: DIResolver.() -> T): State<T> =
18+
// TODO: Use qualifiedName once JS supports it
19+
rememberOnViewModel(key = "${T::class.simpleName}|$key") {
20+
this@derivedState.derived { block() }
21+
}.collectAsState()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.ensody.reactivestate.compose
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.currentCompositeKeyHash
5+
import androidx.lifecycle.ViewModel
6+
import androidx.lifecycle.viewmodel.compose.viewModel
7+
import com.ensody.reactivestate.ExperimentalReactiveStateApi
8+
import com.ensody.reactivestate.InternalReactiveStateApi
9+
10+
@ExperimentalReactiveStateApi
11+
@OptIn(InternalReactiveStateApi::class)
12+
@Composable
13+
public inline fun <reified T> rememberOnViewModel(key: Any? = null, crossinline block: () -> T): T {
14+
val realKey = key ?: currentCompositeKeyHash.toString()
15+
// TODO: Use qualifiedName once JS supports it
16+
val fullKey = "rememberOnViewModel:${T::class.simpleName}:$realKey"
17+
return viewModel(key = fullKey) { RememberViewModel(block()) }.value
18+
}
19+
20+
@InternalReactiveStateApi
21+
public class RememberViewModel<T>(public val value: T) : ViewModel()

reactivestate-compose/src/composeMain/kotlin/com/ensody/reactivestate/compose/ViewModelExt.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public inline fun <reified T : Any?> onViewModel(
7171
crossinline provider: ReactiveStateContext.() -> T,
7272
): State<T> {
7373
// TODO: Use qualifiedName once JS supports it
74-
val fullKey = (key ?: "") + ":onViewModel:${T::class.simpleName}"
74+
val fullKey = "onViewModel:${T::class.simpleName}:$key"
7575
val storage = rememberSaveable<MutableMap<String, Any?>> { mutableMapOf() }
7676
return viewModel(viewModelStoreOwner = viewModelStoreOwner, key = fullKey) {
7777
WrapperViewModel { viewModelScope ->

reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/DI.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ public class DIImpl {
103103
get(state.factory)()
104104
}
105105
deps[klass]?.also {
106-
// TODO: Can we set both in a single go?
107106
it.versionOfDependencies.value = 0
108107
it.factory.value = factory
109108
} ?: run { deps[klass] = State(newValue, MutableStateFlow(factory)) }

0 commit comments

Comments
 (0)