Skip to content

Commit d2dc85a

Browse files
committed
wip
1 parent b70031b commit d2dc85a

File tree

4 files changed

+100
-2
lines changed

4 files changed

+100
-2
lines changed

Sources/ComposableArchitecture/Documentation.docc/Articles/MigrationGuides.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ APIs, and these guides contain tips to do so.
1414
1515
## Topics
1616

17+
- <doc:MigratingTo1.19>
18+
- <doc:MigratingTo1.18>
1719
- <doc:MigratingTo1.17.1>
1820
- <doc:MigratingTo1.17>
1921
- <doc:MigratingTo1.16>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Migrating to 1.18
2+
3+
Stores now automatically cancel their in-flight effects when they deallocate. And another UIKit
4+
navigation helper has been introduced.
5+
6+
## An effect lifecycle change
7+
8+
In previous versions of the Composable Architecture, a root store's effects continued to run even
9+
after the store's lifetime. In 1.18, this leak has been fixed, and a root store's effects will be
10+
cancelled when the store deallocates.
11+
12+
If you depend on a store's fire-and-forget effect to outlive the store, for example if you want to
13+
ensure an analytics or persistence effect proceeds without cancellation, perform this work in an
14+
unstructured task, instead:
15+
16+
```diff
17+
return .run { _ in
18+
- await analytics.track(/* ... */)
19+
+ Task {
20+
+ await analytics.track(/* ... */)
21+
+ }
22+
}
23+
```
24+
25+
## A UIKit navigation helper
26+
27+
Our [Swift Navigation](https://github.com/pointfreeco/swift-navigation) library ships with many
28+
UIKit tools, and the Composable Architecture integrates with many of them, but up till now it has
29+
lacked support for trait-based navigation by pushing an element of ``StackState``.
30+
31+
This has been fixed with a new endpoint on the `push` trait that takes a `state` parameter:
32+
33+
```swift
34+
traitCollection.push(state: Path.State.detail(/* ... */))
35+
```
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Migrating to 1.19
2+
3+
Store internals have been rewritten for performance and future features, and are now compatible with
4+
SwiftUI's `@StateObject` property wrapper.
5+
6+
## Overview
7+
8+
There are no steps needed to migrate to 1.19 of the Composable Architecture, but there are a number
9+
of changes and improvements that have been made to the `Store` that one should be aware of.
10+
11+
## Store internals rewrite
12+
13+
The store's internals have been rewritten to improved performance and to pave the way for future
14+
features. While this should not be a breaking change, with any rewrite it is important to thoroughly
15+
test your application after upgrading.
16+
17+
## StateObject compatibility
18+
19+
SwiftUI's `@State` and `@StateObject` allow a view to own a value or object over time, ensuring that
20+
when a parent view is recomputed, the view-local state isn't recreated from scratch.
21+
22+
One important difference between `@State` and `@StateObject` is that `@State`'s initializer is
23+
eager, while `@StateObject`'s is lazy. Because of this, if you initialize a root `Store` to be held
24+
in `@State`, stores will be initialized (and immediately discarded) whenever the parent view's body
25+
is computed.
26+
27+
To avoid the creation of these stores, one can now assign the store to a `@StateObject`, instead:
28+
29+
```swift
30+
struct FeatureView: View {
31+
@StateObject var store: StoreOf<Feature>
32+
33+
init() {
34+
_store = StateObject(
35+
// This expression is only evaluated the first time the parent view is computed.
36+
wrappedValue: Store(initialState: Feature.State()) {
37+
Feature()
38+
}
39+
)
40+
}
41+
42+
var body: some View { /* ... */ }
43+
}
44+
```
45+
46+
> Important: The store's `ObservableObject` conformance does not have any impact on the actual
47+
> observability of the store. You should continue to rely on the ``ObservableState()`` macro for
48+
> observation.
49+
50+
## Initial actions
51+
52+
A new `initialAction` has been introduced to the `Store` that will immediately kick off an initial
53+
action when the store is created. This is an alternative to waiting for an `onAppear` or `task`
54+
view modifier to evaluate.
55+
56+
```swift
57+
Store(initialState: Feature.State(), initialAction: .initialize) {
58+
Feature()
59+
}
60+
```

Sources/ComposableArchitecture/Observation/Store+Observation.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ extension ObservedObject.Wrapper {
207207
self[
208208
dynamicMember:
209209
\.[
210-
id: self[dynamicMember: \.__currentState].wrappedValue[keyPath: state]
210+
id: self[dynamicMember: \._currentState].wrappedValue[keyPath: state]
211211
.flatMap(_identifiableID),
212212
state: state,
213213
action: action,
@@ -220,8 +220,9 @@ extension ObservedObject.Wrapper {
220220
]
221221
}
222222
}
223+
223224
extension Store {
224-
fileprivate var __currentState: State {
225+
fileprivate var _currentState: State {
225226
get { currentState }
226227
set {}
227228
}

0 commit comments

Comments
 (0)