Reaktiv
0.15.15indexedPowerful MVLI library enhances state management and navigation using unidirectional data flow, type-safe navigation, Jetpack Compose integration, coroutine support, and modular design.
Powerful MVLI library enhances state management and navigation using unidirectional data flow, type-safe navigation, Jetpack Compose integration, coroutine support, and modular design.
Surfaced from shared tags and platforms — no rankings paid for.
Reaktiv is a powerful MVLI (Model-View-Logic-Intent) library for Kotlin Multiplatform, designed to simplify state management and navigation in modern applications. It provides a robust architecture for building scalable and maintainable applications across various platforms.
The foundation of Reaktiv providing the MVLI architecture components:
ModuleWithLogic<S, A, L> - Type-safe module definition with state, actions, and logicStore - Central state manager coordinating all modulesLearn more about the Core module
A comprehensive type-safe navigation system:
Learn more about the Navigation module
Jetpack Compose integration for reactive UI:
StoreProvider - Provide store to Compose hierarchycomposeState<S>() - Observe module state as Compose StaterememberDispatcher() - Access dispatch functionrememberLogic<M, L>() - Access typed module logicLearn more about the Compose module
Real-time debugging and state inspection:
Learn more about the DevTools module
Automatic logic method tracing with DevTools integration:
ModuleLogic methods are traced at compile timeplugins {
id("io.github.syrou.reaktiv.tracing") version "<version>"
}
reaktivTracing {
enabled.set(true)
buildTypes.set(setOf("staging")) // Optional: limit to specific build types
}
Learn more about the Tracing plugin
Add the dependencies to your project:
// build.gradle.kts
plugins {
// Optional: Automatic logic tracing
id("io.github.syrou.reaktiv.tracing") version "<version>"
}
dependencies {
implementation("io.github.syrou:reaktiv-core:<version>")
implementation("io.github.syrou:reaktiv-navigation:<version>")
implementation("io.github.syrou:reaktiv-compose:<version>")
// Optional: DevTools support
implementation("io.github.syrou:reaktiv-devtools:<version>")
}
val navigationModule = createNavigationModule {
rootGraph {
entry(HomeScreen)
screens(HomeScreen, ProfileScreen, SettingsScreen)
graph("auth") {
entry(LoginScreen)
screens(LoginScreen, SignUpScreen)
}
}
notFoundScreen(NotFoundScreen)
}
val store = createStore {
module(CounterModule)
module(navigationModule)
middlewares(loggingMiddleware)
coroutineContext(Dispatchers.Default)
}
@Composable
fun App() {
StoreProvider(store) {
NavigationRender(modifier = Modifier.fillMaxSize())
}
}
@Composable
fun CounterScreen {
state composeState<CounterState>()
dispatch = rememberDispatcher()
logic = rememberLogic<CounterModule, CounterLogic>()
scope = rememberCoroutineScope()
Column {
Text()
Button(onClick = { dispatch(CounterAction.Increment) }) {
Text()
}
Button(onClick = { scope.launch { logic.incrementDelayed() } }) {
Text()
}
}
}
Reaktiv integrates with Swift via SKIE. The recommended pattern is to expose module instances as typed properties on your SDK class so Swift has direct, typed access to them:
// Kotlin — retain module instances on your SDK class
class AppSDK {
val navigationModule = createNavigationModule { ... }
val counterModule = CounterModule
val store = createStore {
module(navigationModule)
module(counterModule)
}
}
Swift can then use the module's built-in interop methods to observe state and access logic:
// Observe state (non-suspend, works directly in Swift)
let stateFlow = SDKManager.shared.sdk.counterModule
.selectStateFlowNonSuspend(store: store)
// Access logic (suspend — SKIE bridges this as async)
let logic = try await SDKManager.shared.sdk.counterModule
.selectLogicTyped(store: store)
If a direct module reference is not available, use getRegisteredModules() as a fallback:
let counterModule = store.getRegisteredModules()
.first { $0 is CounterModule } as? CounterModule
// Using the navigation DSL
scope.launch {
store.navigation {
navigateTo("profile") {
putString("userId", "123")
}
}
}
// Type-safe navigation
scope.launch {
store.navigation {
navigateTo<ProfileScreen> {
put("user", userObject)
}
}
}
// Deep link with backstack synthesis
scope.launch {
store.navigation {
navigateTo("auth/signup/verify", synthesizeBackstack = true)
}
}
// Pop with fallback for deep links
scope.launch {
store.navigation {
popUpTo(, inclusive = , fallback = )
}
}
┌─────────────────────────────────────────────────────────────┐
│ Store │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Module A │ │ Module B │ │ NavigationModule │ │
│ │ ┌───────┐ │ │ ┌───────┐ │ │ ┌───────────────┐ │ │
│ │ │ State │ │ │ │ State │ │ │ │ NavigationState│ │ │
│ │ └───────┘ │ │ └───────┘ │ │ └───────────────┘ │ │
│ │ ┌───────┐ │ │ ┌───────┐ │ │ ┌───────────────┐ │ │
│ │ │ Logic │ │ │ │ Logic │ │ │ │NavigationLogic│ │ │
│ │ └───────┘ │ │ └───────┘ │ │ └───────────────┘ │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Middleware Chain │ │
│ │ Logging → Analytics → DevTools → ... → Reducer │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Compose UI Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ composeState│ │rememberLogic│ │ NavigationRender │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Reaktiv is released under the Apache License Version 2.0. See the LICENSE file for details.
StoreAccessor - Interface for accessing state, logic, and dispatchCustomTypeRegistrar for polymorphic serializationHighPriorityAction for urgent action processingReaktivDebug utilities for development loggingonLifecycleCreated() with BackstackLifecycle for visibility tracking and cleanupParams class with typed access and serializationselect<S, R>() - Derived state with custom selectorsNavigationRender - Render navigation state with animations
data class CounterState(val count: Int = 0) : ModuleState
sealed class CounterAction : ModuleAction(CounterModule::class) {
data object Increment : CounterAction()
data object Decrement : CounterAction()
data class SetCount(val value: Int) : CounterAction()
}
class CounterLogic(val storeAccessor: StoreAccessor) : ModuleLogic() {
suspend fun incrementDelayed() {
delay(1000)
storeAccessor.dispatch(CounterAction.Increment)
}
suspend fun fetchAndSetCount() {
val count = api.fetchCount()
storeAccessor.dispatch(CounterAction.SetCount(count))
}
}
object CounterModule : ModuleWithLogic<CounterState, CounterAction, CounterLogic> {
override val initialState = CounterState()
override val reducer: (CounterState, CounterAction) -> CounterState = { state, action ->
when (action) {
is CounterAction.Increment -> state.copy(count = state.count + 1)
is CounterAction.Decrement -> state.copy(count = state.count - 1)
is CounterAction.SetCount -> state.copy(count = action.value)
}
}
override val createLogic: (StoreAccessor) -> CounterLogic = { CounterLogic(it) }
}