close
Skip to content

feat: add Effect.observe for @Observable store observation#6

Merged
couchdeveloper merged 1 commit into
mainfrom
develop
May 12, 2026
Merged

feat: add Effect.observe for @Observable store observation#6
couchdeveloper merged 1 commit into
mainfrom
develop

Conversation

@couchdeveloper
Copy link
Copy Markdown
Owner

Add ObservationHelpers.swift to the library with two public APIs:

  • Effect.observe(_:keyPath:name:priority:handler:) — observes a key path on an @observable object passed directly. Returns a named, cancellable task effect.

  • Effect.observe(_envKeyPath:keyPath:name:priority:handler:) — env key path overload; resolves the object from Env inside the task, so nothing is captured at update time.

  • observeKeyPath(_:keyPath:handler:) — free function for use inside custom .task effects.

On macOS/iOS 26+ uses Observations.untilFinished (structured, cooperative cancellation). On earlier OS versions falls back to recursive withObservationTracking. KeyPath sendability is handled internally via a private SendableKeyPath<Root, Value>: @unchecked Sendable wrapper, so callers require no SE-0418 flag and no & Sendable annotation.

Package.swift: enable InferSendableFromCaptures for both targets.

README.md: update Recipes section with the Observe an external @observable store recipe, covering both overloads.

Add RemoteCounter example demonstrating the pattern: a @mainactor CounterStore observed via .observe(.store, keyPath: .count), with all writes going through the store's own event API.

Add Documentation/ArchitecturalComparison.md comparing EffectView against MVVM, Redux, TCA, Elm, and Elixir/GenServer across state model, effect model, task lifecycle, dispatch semantics, and testability.

Add ObservationHelpers.swift to the library with two public APIs:

- Effect.observe(_:keyPath:name:priority:handler:) — observes a key
  path on an @observable object passed directly. Returns a named,
  cancellable task effect.

- Effect.observe(_envKeyPath:keyPath:name:priority:handler:) — env key
  path overload; resolves the object from Env inside the task, so
  nothing is captured at update time.

- observeKeyPath(_:keyPath:handler:) — free function for use inside
  custom .task effects.

On macOS/iOS 26+ uses Observations.untilFinished (structured, cooperative
cancellation). On earlier OS versions falls back to recursive
withObservationTracking. KeyPath sendability is handled internally via a
private SendableKeyPath<Root, Value>: @unchecked Sendable wrapper, so
callers require no SE-0418 flag and no & Sendable annotation.

Package.swift: enable InferSendableFromCaptures for both targets.

README.md: update Recipes section with the Observe an external
@observable store recipe, covering both overloads.

Add RemoteCounter example demonstrating the pattern: a @mainactor
CounterStore observed via .observe(\.store, keyPath: \.count), with all
writes going through the store's own event API.

Add Documentation/ArchitecturalComparison.md comparing EffectView
against MVVM, Redux, TCA, Elm, and Elixir/GenServer across state model,
effect model, task lifecycle, dispatch semantics, and testability.
@couchdeveloper couchdeveloper merged commit a3d8424 into main May 12, 2026
1 check passed
@couchdeveloper couchdeveloper deleted the develop branch May 12, 2026 17:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant