From d7e53338ab085fe24d1881d5b9fb704257743b06 Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Fri, 31 Oct 2025 00:50:59 +0900 Subject: [PATCH 01/11] docs: Add thread-safety warning for @unchecked Sendable in Middleware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add warning block and inline comments to clarify that @unchecked Sendable bypasses Swift's concurrency checks and requires manual thread-safety guarantees. Explain that this is safe in Flow due to MainActor isolation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/Flow.docc/Middleware.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/Flow/Flow.docc/Middleware.md b/Sources/Flow/Flow.docc/Middleware.md index 35bf97d..0fb8049 100644 --- a/Sources/Flow/Flow.docc/Middleware.md +++ b/Sources/Flow/Flow.docc/Middleware.md @@ -52,10 +52,14 @@ struct AnalyticsMiddleware: ActionMiddleware { Use `final class` with `@unchecked Sendable` when middleware needs to track state: +> Warning: `@unchecked Sendable` bypasses Swift's thread-safety checks. You must ensure thread-safety manually. This is safe in Flow because all middleware operations run on the MainActor. + ```swift import Flow final class TimingMiddleware: ActionMiddleware, @unchecked Sendable { + // ⚠️ @unchecked Sendable: We guarantee thread-safety because Flow ensures + // all middleware methods execute on MainActor with defaultIsolation let id = "TimingMiddleware" private var startTimes: [String: Date] = [:] From 21a527e9476ed816d454e05fea79d38a3061cd57 Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Fri, 31 Oct 2025 00:56:21 +0900 Subject: [PATCH 02/11] docs: Improve concept guidance in Getting Started MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhance step titles to briefly introduce key concepts (State, Actions, ActionHandler, Store) and add a guidance note directing readers to CoreConcepts for detailed explanations. This maintains the quick-start focus while providing better context. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/Flow.docc/GettingStarted.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Sources/Flow/Flow.docc/GettingStarted.md b/Sources/Flow/Flow.docc/GettingStarted.md index e2d0384..f9448d8 100644 --- a/Sources/Flow/Flow.docc/GettingStarted.md +++ b/Sources/Flow/Flow.docc/GettingStarted.md @@ -46,9 +46,9 @@ dependencies: [ ## Build a Counter App -### Step 1 +### Step 1: Define Your Feature -Create a Feature and define State, Action, and Handler. +Create a Feature that groups **State** (data), **Actions** (events), and **ActionHandler** (logic). ```swift import Flow @@ -85,9 +85,9 @@ struct CounterFeature: Feature { } ``` -### Step 2 +### Step 2: Create Your View -Create a View and integrate the Store. +Create a View and integrate the **Store**, which manages state and coordinates actions. ```swift import SwiftUI @@ -122,6 +122,8 @@ struct CounterView: View { That's it! You've implemented the basic functionality. +> **Understanding the Code**: To learn what Feature, State, Action, ActionHandler, and Store mean and how they work together, continue to . + ## Next Steps Now that you've built a counter app, let's dive deeper into Flow's architecture: From 18f9b1f2d1cc216634128dea73b0b94e26931fa8 Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Fri, 31 Oct 2025 00:58:55 +0900 Subject: [PATCH 03/11] docs: Add Quick Reference table to Core Elements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a reference table summarizing the five core elements with their purposes and key APIs. This provides readers with a quick overview before diving into detailed sections. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/Flow.docc/CoreElements.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Sources/Flow/Flow.docc/CoreElements.md b/Sources/Flow/Flow.docc/CoreElements.md index 3e571e2..2df98c8 100644 --- a/Sources/Flow/Flow.docc/CoreElements.md +++ b/Sources/Flow/Flow.docc/CoreElements.md @@ -14,6 +14,16 @@ Flow consists of five core elements: These elements work together to build applications. +## Quick Reference + +| Element | Purpose | Key APIs | +|---------|---------|----------| +| **Store** | Manages state and coordinates actions | `send()`, `state` property | +| **Feature** | Groups State, Actions, and Handler | `State`, `Action`, `handle()` | +| **ActionHandler** | Processes actions and returns tasks | Returns `ActionTask` | +| **ActionResult** | Defines the result type of actions | `Void` or custom type | +| **ActionTask** | Manages async execution | `.none`, `.run`, `.just`, `.cancel`, `.concatenate` | + ## Store **Store** manages state, receives actions from views, sends them to handlers, and processes results. From 3a2d1a1c35ba1600d66f297d63984e5a81f7ca6e Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Fri, 31 Oct 2025 01:01:48 +0900 Subject: [PATCH 04/11] docs: Expand Store, Feature, and ActionHandler sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add detailed explanations and practical examples for: - Store: Key responsibilities, @State lifecycle, sending actions - Feature: Benefits (cohesion, reusability, type safety) with complete implementation - ActionHandler: How it works with sync/async examples This balances the document sections and provides better guidance for developers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/Flow.docc/CoreElements.md | 73 +++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/Sources/Flow/Flow.docc/CoreElements.md b/Sources/Flow/Flow.docc/CoreElements.md index 2df98c8..5658ad2 100644 --- a/Sources/Flow/Flow.docc/CoreElements.md +++ b/Sources/Flow/Flow.docc/CoreElements.md @@ -28,6 +28,15 @@ These elements work together to build applications. **Store** manages state, receives actions from views, sends them to handlers, and processes results. +**Key responsibilities:** +- Holds the current state +- Receives actions from views via `send()` +- Coordinates with ActionHandler to process actions +- Returns `ActionTask` for async result handling + +**Why use `@State`?** +Store is held with `@State` to tie its lifecycle to the view. When the view appears, the store initializes; when dismissed, it cleans up automatically. + ```swift import SwiftUI import Flow @@ -47,9 +56,29 @@ var body: some View { } ``` +**Sending actions:** + +```swift +// Fire-and-forget (common for state-only updates) +store.send(.increment) + +// Handle results for navigation, validation, etc. +Task { + let result = await store.send(.save).value + if case .success = result { + // Navigate or show confirmation + } +} +``` + ## Feature -**Feature** defines State, Action, and ActionHandler in one place. +**Feature** groups State, Actions, and ActionHandler in one place, providing a complete definition of a feature's behavior. + +**Why use Feature?** +- **Cohesion** - Related logic stays together +- **Reusability** - Easy to test and reuse across views +- **Type safety** - State, Action, and ActionResult are strongly typed ```swift import Flow @@ -68,7 +97,18 @@ struct UserFeature: Feature { func handle() -> ActionHandler { ActionHandler { action, state in - // Business logic goes here + switch action { + case .load: + state.isLoading = true + return .run { state in + let user = try await api.fetchUser() + state.user = user + state.isLoading = false + } + case .logout: + state.user = nil + return .none + } } } } @@ -78,6 +118,35 @@ struct UserFeature: Feature { **ActionHandler** receives actions and current state, updates state, and returns an ActionTask. +**How it works:** +The handler is a closure that receives two parameters: +- **action** - The action to process +- **state** - The current state (mutable) + +You can update state directly and return a task describing any async work. + +**Example:** + +```swift +ActionHandler { action, state in + switch action { + case .increment: + state.count += 1 // Synchronous state update + return .none // No async work + + case .fetchData: + state.isLoading = true + return .run { state in // Async work + let data = try await api.fetch() + state.data = data + state.isLoading = false + } + } +} +``` + +**Generic type parameters:** + ```swift ActionHandler ``` From 05a72eeaac6f2b03923d42ca92dcab8a1555015e Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Fri, 31 Oct 2025 01:03:14 +0900 Subject: [PATCH 05/11] docs: Simplify Result-Returning Actions example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace complex parent-child navigation example with a simpler login validation example. The new example better demonstrates: - Basic ActionResult definition - .just() for immediate results - .run with result returns - Result type handling Moves advanced parent-child patterns to PracticalGuide reference. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/Flow.docc/CoreConcepts.md | 104 ++++++++++++++----------- 1 file changed, 60 insertions(+), 44 deletions(-) diff --git a/Sources/Flow/Flow.docc/CoreConcepts.md b/Sources/Flow/Flow.docc/CoreConcepts.md index 9b41b80..feef3ce 100644 --- a/Sources/Flow/Flow.docc/CoreConcepts.md +++ b/Sources/Flow/Flow.docc/CoreConcepts.md @@ -54,62 +54,72 @@ struct CounterView: View { Actions can return results through `ActionTask`. The result type (`ActionResult`) can be defined for each Feature. -In this example, a child view returns a selection result to the parent, which handles navigation: +**Basic example:** ```swift import SwiftUI import Flow -struct ParentView: View { - @Environment(\.navigator) private var navigator - - var body: some View { - ChildView { selectedId in - await navigator.navigate(to: .detail(id: selectedId)) - } - } -} - -struct ChildView: View { - @State private var store = Store( - initialState: .init(), - feature: ChildFeature() - ) - let onSelect: (String) async -> Void - - var body: some View { - Button("Select") { - Task { - let result = await store.send(.select).value - if case .success(.selected(let id)) = result { - await onSelect(id) - } - } - } - } -} - -struct ChildFeature: Feature { +struct LoginFeature: Feature { @Observable final class State { - var selectedId = "" + var username = "" + var password = "" } enum Action: Sendable { - case select + case login } enum ActionResult: Sendable { - case selected(id: String) + case success + case invalidCredentials + case networkError } func handle() -> ActionHandler { ActionHandler { action, state in switch action { - case .select: - return .run { state in - let id = state.selectedId - return .selected(id: id) + case .login: + if state.username.isEmpty || state.password.isEmpty { + return .just(.invalidCredentials) // Return result immediately + } + return .run { state in // Async work with result + do { + try await api.login(state.username, state.password) + return .success + } catch { + return .networkError + } + } + } + } + } +} + +struct LoginView: View { + @State private var store = Store( + initialState: .init(), + feature: LoginFeature() + ) + + var body: some View { + VStack { + TextField("Username", text: $store.state.username) + SecureField("Password", text: $store.state.password) + Button("Login") { + Task { + let result = await store.send(.login).value + switch result { + case .success(.success): + print("Navigate to home") + case .success(.invalidCredentials): + print("Show error: Invalid credentials") + case .success(.networkError): + print("Show error: Network error") + case .failure(let error): + print("Unexpected error: \(error)") + } } } } @@ -117,13 +127,19 @@ struct ChildFeature: Feature { } ``` -This implementation provides: -- `ChildFeature` returns selection results to the parent via `ActionResult` -- `ParentView` receives results through the `onSelect` callback -- Parent controls side effects like navigation -- Everything stays within the view tree, allowing dependencies to be tracked +**Key concepts:** +- **ActionResult** - Define custom result types for your Feature +- **`.just(result)`** - Return results immediately (synchronous) +- **`.run { ... return result }`** - Return results after async work +- **`await store.send().value`** - Wait for and receive the result +- **`Result`** - Results are wrapped in Swift's Result type + +**Use cases for ActionResult:** +- Form validation with specific error types +- Navigation decisions based on action outcomes +- Showing different toasts based on success/failure patterns -See for more details. +For parent-child communication patterns and more advanced examples, see . ### @Observable Support From 2ce0b0abd62ea7f97cec95a770b745c91790f3da Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Fri, 31 Oct 2025 01:05:34 +0900 Subject: [PATCH 06/11] docs: Add error handling to Practical Guide examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhance error handling across multiple patterns: - Task Cancellation: Add cancelInFlight explanation and .catch example - Parallel Processing: Add .catch for handling failed concurrent operations - Parent-Child Communication: Add .failure case handling These additions demonstrate proper error handling in real-world scenarios. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/Flow.docc/PracticalGuide.md | 26 +++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Sources/Flow/Flow.docc/PracticalGuide.md b/Sources/Flow/Flow.docc/PracticalGuide.md index 9435d56..a0d5afc 100644 --- a/Sources/Flow/Flow.docc/PracticalGuide.md +++ b/Sources/Flow/Flow.docc/PracticalGuide.md @@ -85,6 +85,10 @@ func handle() -> ActionHandler { Cancel previous requests with `.cancellable(id:cancelInFlight:)` for user input operations like search. +**Understanding `cancelInFlight`:** +- `true` - Cancels any running task with the same ID before starting the new one +- `false` - Allows multiple tasks with the same ID to run concurrently + ```swift import Flow @@ -100,6 +104,16 @@ func handle() -> ActionHandler { state.isSearching = false } .cancellable(id: "search", cancelInFlight: true) + .catch { error, state in + state.isSearching = false + // Note: Cancellation errors are handled automatically, + // only explicit errors from api.search() reach here + if error is CancellationError { + // Task was cancelled, no action needed + } else { + state.errorMessage = error.localizedDescription + } + } case .cancelSearch: state.isSearching = false @@ -120,12 +134,18 @@ func handle() -> ActionHandler { ActionHandler { action, state in switch action { case .loadAll: + state.isLoading = true return .run { state in async let users = api.fetchUsers() async let posts = api.fetchPosts() state.users = try await users state.posts = try await posts + state.isLoading = false + } + .catch { error, state in + state.isLoading = false + state.errorMessage = "Failed to load data: \(error.localizedDescription)" } } } @@ -263,8 +283,12 @@ struct ChildView: View { Button("Validate") { Task { let result = await store.send(.validate).value - if case .success(let validationResult) = result { + switch result { + case .success(let validationResult): onValidate(validationResult) + case .failure(let error): + print("Validation error: \(error)") + // Handle unexpected errors (network issues, etc.) } } } From b52b32c139ecb2ae646a8cd8915ae4559cded8dc Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Fri, 31 Oct 2025 01:09:19 +0900 Subject: [PATCH 07/11] docs: Add multiple middleware usage section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add section explaining how to chain multiple middleware with .use() and describe the execution order (beforeAction: top-down, afterAction: bottom-up, onError: top-down). Includes practical example combining logging, analytics, and error reporting. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/Flow.docc/Middleware.md | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Sources/Flow/Flow.docc/Middleware.md b/Sources/Flow/Flow.docc/Middleware.md index 0fb8049..e60cf1e 100644 --- a/Sources/Flow/Flow.docc/Middleware.md +++ b/Sources/Flow/Flow.docc/Middleware.md @@ -122,6 +122,39 @@ func handle() -> ActionHandler { [MyFeature] ✗ Error: Network error (0.145s) ``` +## Using Multiple Middleware + +Chain multiple middleware with `.use()` to compose cross-cutting concerns. + +**Example:** + +```swift +import Flow + +func handle() -> ActionHandler { + ActionHandler { action, state in + // Action processing logic + } + .use(LoggingMiddleware(category: "UserFeature")) + .use(AnalyticsMiddleware(analytics: .shared)) + .use(ErrorReportingMiddleware(reporter: .production)) +} +``` + +**Execution order:** + +Middleware executes in the order they are added: + +1. **beforeAction** - Top to bottom (Logging → Analytics → Error Reporting) +2. **Action processing** - Your handler executes +3. **afterAction** - Bottom to top (Error Reporting → Analytics → Logging) +4. **onError** - Top to bottom (Logging → Analytics → Error Reporting) + +This order ensures that: +- Logging middleware sees all actions first +- Error reporting catches all failures +- Analytics tracks after processing completes + ## Next Steps Now that you can add cross-cutting concerns with middleware, let's learn practical patterns: From eb8aaa32f04a80a80a7604bfc27b4dd995684a60 Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Fri, 31 Oct 2025 01:10:21 +0900 Subject: [PATCH 08/11] docs: Expand .just() explanation in Core Elements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add detailed explanation comparing .just() with .none and listing common use cases (validation, state calculations, cache hits). This clarifies when to use .just() for synchronous results vs .run for async results. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/Flow.docc/CoreElements.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Sources/Flow/Flow.docc/CoreElements.md b/Sources/Flow/Flow.docc/CoreElements.md index 5658ad2..5105a9d 100644 --- a/Sources/Flow/Flow.docc/CoreElements.md +++ b/Sources/Flow/Flow.docc/CoreElements.md @@ -164,7 +164,16 @@ Type parameters: **Return results from synchronous processing:** -Use `.just()` to return results immediately. +Use `.just()` to return results immediately without async work. + +`.just()` is similar to `.none`, but returns a custom result value: +- **`.none`** - Returns `Void` (no result) +- **`.just(result)`** - Returns a specific result value + +Common uses: +- Validation results +- Calculations based on current state +- Cache hits or default values ```swift ActionHandler { action, state in From c47f25dec644a9f1320e35d5bec07114acb763b5 Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Fri, 31 Oct 2025 01:13:24 +0900 Subject: [PATCH 09/11] docs: Simplify Task Priority section with reference table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace four separate code examples with a concise reference table and two focused examples. Add note clarifying that priority affects scheduling but doesn't guarantee order. Makes the section more scannable while preserving essential information. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/Flow.docc/PracticalGuide.md | 35 +++++++++++------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/Sources/Flow/Flow.docc/PracticalGuide.md b/Sources/Flow/Flow.docc/PracticalGuide.md index a0d5afc..952a264 100644 --- a/Sources/Flow/Flow.docc/PracticalGuide.md +++ b/Sources/Flow/Flow.docc/PracticalGuide.md @@ -154,7 +154,18 @@ func handle() -> ActionHandler { ## Task Priority -Set task priority to execute important operations first. +Set task priority to control how the system schedules async operations. + +**Priority levels:** + +| Priority | When to Use | Example Use Cases | +|----------|-------------|-------------------| +| `.high` | User is actively waiting for results | Critical data loading, search results | +| `.userInitiated` | User-triggered operations | Button actions, form submissions | +| `.utility` | Improve UX but not urgent | Prefetching, caching next page | +| `.background` | Can run anytime | Analytics uploads, logs, cleanup | + +**Example:** ```swift import Flow @@ -163,7 +174,7 @@ func handle() -> ActionHandler { ActionHandler { action, state in switch action { case .loadCriticalData: - // Critical data loading that users are waiting for + // User is waiting for this data return .run { state in let data = try await api.fetchCriticalData() state.data = data @@ -171,33 +182,19 @@ func handle() -> ActionHandler { .priority(.high) case .uploadAnalytics: - // Analytics data upload in background + // Background task, can run anytime return .run { state in try await analytics.upload(state.events) state.events.removeAll() } .priority(.background) - - case .loadUserProfile: - // User-initiated operation - return .run { state in - let profile = try await api.fetchProfile() - state.profile = profile - } - .priority(.userInitiated) - - case .prefetchNextPage: - // Utility operation (prefetch cache, etc.) - return .run { state in - let nextPage = try await api.fetchNextPage() - state.cachedPages.append(nextPage) - } - .priority(.utility) } } } ``` +> Note: Priority affects scheduling but doesn't guarantee execution order. Use `.concatenate` when strict ordering is required. + ## Method Chaining Combine multiple methods to set priority, cancellation, error handling, and more on tasks. From 3c48905acc5e6c7b17c0a584dbd01c4307b8fc5f Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Fri, 31 Oct 2025 01:17:02 +0900 Subject: [PATCH 10/11] docs: Add Overview section and quick example to Flow landing page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comprehensive Overview section with: - Design philosophy (view-local, unidirectional, type-safe, concurrency) - Quick counter example for 30-second understanding - Architecture diagram reference - Comparison with global store architectures This helps visitors quickly assess if Flow fits their needs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/Flow.docc/Flow.md | 57 ++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/Sources/Flow/Flow.docc/Flow.md b/Sources/Flow/Flow.docc/Flow.md index 1756363..4df9998 100644 --- a/Sources/Flow/Flow.docc/Flow.md +++ b/Sources/Flow/Flow.docc/Flow.md @@ -2,6 +2,63 @@ A library for managing state in SwiftUI applications in a type-safe way. Flow provides a unidirectional data flow architecture and supports Swift 6 Approachable Concurrency. +## Overview + +Flow brings predictable state management to SwiftUI with a view-local approach. Unlike architectures with global stores (Redux, TCA), Flow keeps state scoped to views, making it easier to reason about lifecycle and dependencies. + +**Design Philosophy:** +- **View-local state** - No singleton stores to manage +- **Unidirectional flow** - Actions → Handler → State → View +- **Type-safe results** - Actions can return typed results for navigation and error handling +- **Concurrency-first** - Built for Swift 6 with MainActor isolation + +**Quick Example:** + +```swift +import SwiftUI +import Flow + +// Define your feature +struct CounterFeature: Feature { + @Observable final class State { + var count = 0 + } + + enum Action: Sendable { + case increment + } + + func handle() -> ActionHandler { + ActionHandler { action, state in + state.count += 1 + return .none + } + } +} + +// Use in your view +struct CounterView: View { + @State private var store = Store( + initialState: .init(), + feature: CounterFeature() + ) + + var body: some View { + Button("Count: \(store.state.count)") { + store.send(.increment) + } + } +} +``` + +For a complete walkthrough, see . + +**Architecture:** + +![Flow Architecture](flow-diagram.svg) + +Actions flow through the handler, update state, and SwiftUI re-renders automatically. + ## Key Features - **No global store** - Each view holds its own state with `@State` From 4f0294c11c9012056414cc12891321afbcdf12de Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Fri, 31 Oct 2025 01:23:17 +0900 Subject: [PATCH 11/11] docs: Add detailed .cancellable() explanation in Core Elements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comprehensive explanation of .cancellable(id:cancelInFlight:) with: - Parameter descriptions (id for identification, cancelInFlight behavior) - Task ID naming conventions - Scoping information This clarifies task cancellation mechanics for developers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/Flow.docc/CoreElements.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Sources/Flow/Flow.docc/CoreElements.md b/Sources/Flow/Flow.docc/CoreElements.md index 5105a9d..814e6dc 100644 --- a/Sources/Flow/Flow.docc/CoreElements.md +++ b/Sources/Flow/Flow.docc/CoreElements.md @@ -272,6 +272,16 @@ return .just(.success) **Execute async processing** +Use `.cancellable(id:cancelInFlight:)` to manage long-running tasks: + +**Parameters:** +- **`id`** - Unique identifier for the task (used for cancellation) +- **`cancelInFlight`** - Behavior when starting a new task with the same ID: + - `true` - Cancels the existing task before starting the new one + - `false` - Allows both tasks to run concurrently + +**Example:** + ```swift return .run { state in let user = try await api.fetchUser() @@ -280,6 +290,11 @@ return .run { state in .cancellable(id: "load-user", cancelInFlight: true) ``` +**Task ID naming:** +- Use descriptive names: `"search"`, `"load-user"`, `"upload-photo"` +- Keep consistent across related actions +- Task IDs are scoped to each Store instance + **Cancel running task** ```swift