
Powerful MVLI library enhances state management and navigation using unidirectional data flow, type-safe navigation, Jetpack Compose integration, coroutine support, and modular design.
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 modulesStoreAccessor - Interface for accessing state, logic, and dispatchCustomTypeRegistrar for polymorphic serializationHighPriorityAction for urgent action processingReaktivDebug utilities for development loggingLearn more about the Core module
A comprehensive type-safe navigation system:
onLifecycleCreated() with BackstackLifecycle for visibility tracking and cleanupParams class with typed access and serializationLearn 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 logicselect<S, R>() - Derived state with custom selectorsNavigationRender - Render navigation state with animationsLearn 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>")
}@Serializable
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(private val storeAccessor: StoreAccessor) : ModuleLogic<CounterAction>() {
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) }
}val navigationModule = createNavigationModule {
rootGraph {
startScreen(HomeScreen)
screens(ProfileScreen, SettingsScreen)
graph("auth") {
startScreen(LoginScreen)
screens(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() {
val state by composeState<CounterState>()
val dispatch = rememberDispatcher()
val logic = rememberLogic<CounterModule, CounterLogic>()
val scope = rememberCoroutineScope()
Column {
Text("Count: ${state.count}")
Button(onClick = { dispatch(CounterAction.Increment) }) {
Text("Increment")
}
Button(onClick = { scope.launch { logic.incrementDelayed() } }) {
Text("Increment Delayed")
}
}
}// 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("home", inclusive = false, fallback = "root")
}
}┌─────────────────────────────────────────────────────────────┐
│ 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.
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 modulesStoreAccessor - Interface for accessing state, logic, and dispatchCustomTypeRegistrar for polymorphic serializationHighPriorityAction for urgent action processingReaktivDebug utilities for development loggingLearn more about the Core module
A comprehensive type-safe navigation system:
onLifecycleCreated() with BackstackLifecycle for visibility tracking and cleanupParams class with typed access and serializationLearn 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 logicselect<S, R>() - Derived state with custom selectorsNavigationRender - Render navigation state with animationsLearn 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>")
}@Serializable
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(private val storeAccessor: StoreAccessor) : ModuleLogic<CounterAction>() {
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) }
}val navigationModule = createNavigationModule {
rootGraph {
startScreen(HomeScreen)
screens(ProfileScreen, SettingsScreen)
graph("auth") {
startScreen(LoginScreen)
screens(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() {
val state by composeState<CounterState>()
val dispatch = rememberDispatcher()
val logic = rememberLogic<CounterModule, CounterLogic>()
val scope = rememberCoroutineScope()
Column {
Text("Count: ${state.count}")
Button(onClick = { dispatch(CounterAction.Increment) }) {
Text("Increment")
}
Button(onClick = { scope.launch { logic.incrementDelayed() } }) {
Text("Increment Delayed")
}
}
}// 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("home", inclusive = false, fallback = "root")
}
}┌─────────────────────────────────────────────────────────────┐
│ 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.