ronstorm/tca-kit
A lightweight, SwiftUI-first implementation of The Composable Architecture (TCA) patterns with one-way data flow, reducers, and effects. Designed to be easy to drop into SwiftUI apps with low boilerplate and async/await support.
Features
- Store: Manages state and handles actions with @MainActor publishing
- Reducer: Pure functions that handle actions and return effects
- Effect: Represents async side effects with cancellation support
- Dependencies: Environment-based dependency injection for services
- WithStore: SwiftUI helper for ergonomic store usage in views
- TestStore: Testing utility with fluent assertions and transcripts
- CombineBridge: Seamless integration between Combine publishers and TCAKit effects
- SwiftUI-First: Built specifically for SwiftUI with @MainActor integration
- Cross-platform: iOS, macOS, tvOS, and watchOS support
- Lightweight: No external dependencies
- Modern Swift: Swift 5.9+ with Concurrency support
Quick Start
1. Installation
Add TCAKit to your project:
dependencies: [
.package(url: "https://github.com/ronstorm/tca-kit.git", from: "1.0.0")
]2. Basic Usage
import TCAKit
import SwiftUI
// State
struct CounterState {
var count: Int = 0
}
// Actions
enum CounterAction {
case increment, decrement, reset
}
// Reducer
func counterReducer(
state: inout CounterState,
action: CounterAction,
dependencies: Dependencies
) -> Effect<CounterAction> {
switch action {
case .increment: state.count += 1
case .decrement: state.count -= 1
case .reset: state.count = 0
}
return .none
}
// SwiftUI View
struct CounterView: View {
@ObservedObject var store: Store<CounterState, CounterAction>
var body: some View {
WithStore(store) { store in
VStack {
Text("Count: \(store.state.count)")
HStack {
Button("−") { store.send(.decrement) }
Button("Reset") { store.send(.reset) }
Button("+") { store.send(.increment) }
}
}
}
}
}
// Complete App
@main
struct CounterApp: App {
@StateObject private var store: Store<CounterState, CounterAction>
init() {
let dependencies = Dependencies()
self._store = StateObject(wrappedValue: Store(
initialState: CounterState(),
reducer: counterReducer,
dependencies: dependencies
))
}
var body: some Scene {
WindowGroup {
CounterView(store: store)
}
}
}Documentation
Complete Documentation - Comprehensive guide to TCAKit
Core Concepts
- Store - State management and action handling
- Reducer - Pure functions for state updates
- Effect - Async side effects with cancellation
- Dependencies - Dependency injection system
- SwiftUI Integration - Best practices for SwiftUI
Examples
Ready-to-run examples showcasing TCAKit patterns:
BasicCounter - Start Here
Simple counter app demonstrating core TCAKit concepts.
- Files:
BasicCounter.swift(standalone app) - Learn: State, actions, reducers, SwiftUI integration
TodoList - Intermediate
Full-featured todo list with CRUD operations and effects.
- Files:
TodoList.swift+Models.swift(standalone app) - Learn: Complex state, async effects, extending Dependencies, error handling
WeatherApp - Advanced
Weather app with network requests and real-world patterns.
- Files:
WeatherApp.swift+Models.swift(standalone app) - Learn: Network requests, effect cancellation, extending Dependencies, complex state
Quick Start: Copy any example files to your project, add TCAKit dependency, and run immediately! See Examples/SETUP.md for detailed instructions.
Requirements
- iOS 15.0+
- macOS 12.0+
- tvOS 15.0+
- watchOS 8.0+
- Swift 5.9+
- SwiftUI
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
Package Metadata
Repository: ronstorm/tca-kit
Default branch: master
README: README.md