Skip to content

Commit 01d395d

Browse files
authored
Add initializing effect (#181)
1 parent 9721078 commit 01d395d

File tree

12 files changed

+83
-12
lines changed

12 files changed

+83
-12
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1403,7 +1403,8 @@ You can create custom effects that conform to the [`AtomEffect`](https://ra1028.
14031403

14041404
|API|Use|
14051405
|:--|:--|
1406-
|[InitializeEffect](https://ra1028.github.io/swiftui-atom-properties/documentation/atoms/initializeeffect)|Performs an arbitrary action when the atom is initialized.|
1406+
|[InitializingEffect](https://ra1028.github.io/swiftui-atom-properties/documentation/atoms/initializingeffect)|Performs an arbitrary action before the atom is initialized.|
1407+
|[InitializeEffect](https://ra1028.github.io/swiftui-atom-properties/documentation/atoms/initializeeffect)|Performs an arbitrary action after the atom is initialized.|
14071408
|[UpdateEffect](https://ra1028.github.io/swiftui-atom-properties/documentation/atoms/updateeffect)|Performs an arbitrary action when the atom is updated.|
14081409
|[ReleaseEffect](https://ra1028.github.io/swiftui-atom-properties/documentation/atoms/releaseeffect)|Performs an arbitrary action when the atom is released.|
14091410
|[MergedEffect](https://ra1028.github.io/swiftui-atom-properties/documentation/atoms/mergedeffect)|Merges multiple atom effects into one.|

Sources/Atoms/Atoms.docc/Atoms.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Building state by compositing atoms automatically optimizes rendering based on i
3737
### Effects
3838

3939
- ``AtomEffect``
40+
- ``InitializingEffect``
4041
- ``InitializeEffect``
4142
- ``UpdateEffect``
4243
- ``ReleaseEffect``

Sources/Atoms/Core/StoreContext.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,14 +279,15 @@ private extension StoreContext {
279279
for key: AtomKey,
280280
override: Override<Node>?
281281
) -> Node.Produced {
282-
let value = getValue(of: atom, for: key, override: override)
283282
let state = getState(of: atom, for: key)
283+
let currentContext = AtomCurrentContext(store: self)
284+
285+
state.effect.initializing(context: currentContext)
284286

287+
let value = getValue(of: atom, for: key, override: override)
285288
store.state.caches[key] = AtomCache(atom: atom, value: value, initializedScope: currentScope)
286289

287-
let currentContext = AtomCurrentContext(store: self)
288290
state.effect.initialized(context: currentContext)
289-
290291
return value
291292
}
292293

Sources/Atoms/Effect/AtomEffect.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
/// initialized the first time the atom is used, and the instance will be retained
55
/// until the atom is released, thus it allows to declare stateful side effects.
66
///
7+
/// SeeAlso: ``InitializingEffect``
78
/// SeeAlso: ``InitializeEffect``
89
/// SeeAlso: ``UpdateEffect``
910
/// SeeAlso: ``ReleaseEffect``
@@ -14,8 +15,12 @@ public protocol AtomEffect {
1415
/// with other atoms.
1516
typealias Context = AtomCurrentContext
1617

17-
/// A lifecycle event that is triggered when the atom is first used and initialized,
18-
/// or once it is released and re-initialized again.
18+
/// A lifecycle event that is triggered before the atom is first used and initialized,
19+
/// or once it is released and re-initialized.
20+
func initializing(context: Context)
21+
22+
/// A lifecycle event that is triggered after the atom is first used and initialized,
23+
/// or once it is released and re-initialized.
1924
func initialized(context: Context)
2025

2126
/// A lifecycle event that is triggered when the atom is updated.
@@ -26,6 +31,7 @@ public protocol AtomEffect {
2631
}
2732

2833
public extension AtomEffect {
34+
func initializing(context: Context) {}
2935
func initialized(context: Context) {}
3036
func updated(context: Context) {}
3137
func released(context: Context) {}

Sources/Atoms/Effect/InitializeEffect.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
/// An atom effect that performs an arbitrary action when the atom is first used and initialized,
2-
/// or once it is released and re-initialized again.
1+
/// An atom effect that performs an arbitrary action after the atom is first used and initialized,
2+
/// or once it is released and re-initialized.
33
public struct InitializeEffect: AtomEffect {
44
private let action: @MainActor () -> Void
55

6-
/// Creates an atom effect that performs the given action when the atom is initialized.
6+
/// Creates an atom effect that performs the given action after the atom is initialized.
77
public init(perform action: @MainActor @escaping () -> Void) {
88
self.action = action
99
}
1010

11-
/// A lifecycle event that is triggered when the atom is first used and initialized,
12-
/// or once it is released and re-initialized again.
11+
/// A lifecycle event that is triggered after the atom is first used and initialized,
12+
/// or once it is released and re-initialized.
1313
public func initialized(context: Context) {
1414
action()
1515
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// An atom effect that performs an arbitrary action before the atom is first used and initialized,
2+
/// or once it is released and re-initialized.
3+
public struct InitializingEffect: AtomEffect {
4+
private let action: @MainActor () -> Void
5+
6+
/// Creates an atom effect that performs the given action before the atom is initialized.
7+
public init(perform action: @MainActor @escaping () -> Void) {
8+
self.action = action
9+
}
10+
11+
/// A lifecycle event that is triggered before the atom is first used and initialized,
12+
/// or once it is released and re-initialized.
13+
public func initializing(context: Context) {
14+
action()
15+
}
16+
}

Tests/AtomsTests/Core/StoreContextTests.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,13 +1157,15 @@ final class StoreContextTests: XCTestCase {
11571157
_ = context.watch(upstreamAtom, in: TransactionState(key: key))
11581158

11591159
XCTAssertTrue((store.state.states[key]?.effect as? TestEffect) === effect)
1160+
XCTAssertEqual(effect.initializingCount, 1)
11601161
XCTAssertEqual(effect.initializedCount, 1)
11611162
XCTAssertEqual(effect.updatedCount, 0)
11621163
XCTAssertEqual(effect.releasedCount, 0)
11631164

11641165
context.set(1, for: atom)
11651166

11661167
XCTAssertTrue((store.state.states[key]?.effect as? TestEffect) === effect)
1168+
XCTAssertEqual(effect.initializingCount, 1)
11671169
XCTAssertEqual(effect.initializedCount, 1)
11681170
XCTAssertEqual(effect.updatedCount, 1)
11691171
XCTAssertEqual(effect.releasedCount, 0)
@@ -1173,27 +1175,31 @@ final class StoreContextTests: XCTestCase {
11731175
context.set(4, for: atom)
11741176

11751177
XCTAssertTrue((store.state.states[key]?.effect as? TestEffect) === effect)
1178+
XCTAssertEqual(effect.initializingCount, 1)
11761179
XCTAssertEqual(effect.initializedCount, 1)
11771180
XCTAssertEqual(effect.updatedCount, 4)
11781181
XCTAssertEqual(effect.releasedCount, 0)
11791182

11801183
context.set("Updated", for: upstreamAtom)
11811184

11821185
XCTAssertTrue((store.state.states[key]?.effect as? TestEffect) === effect)
1186+
XCTAssertEqual(effect.initializingCount, 1)
11831187
XCTAssertEqual(effect.initializedCount, 1)
11841188
XCTAssertEqual(effect.updatedCount, 5)
11851189
XCTAssertEqual(effect.releasedCount, 0)
11861190

11871191
context.unwatch(atom, subscriber: subscriber)
11881192

11891193
XCTAssertNil(store.state.states[key])
1194+
XCTAssertEqual(effect.initializingCount, 1)
11901195
XCTAssertEqual(effect.initializedCount, 1)
11911196
XCTAssertEqual(effect.updatedCount, 5)
11921197
XCTAssertEqual(effect.releasedCount, 1)
11931198

11941199
context.set(5, for: atom)
11951200

11961201
XCTAssertNil(store.state.states[key])
1202+
XCTAssertEqual(effect.initializingCount, 1)
11971203
XCTAssertEqual(effect.initializedCount, 1)
11981204
XCTAssertEqual(effect.updatedCount, 5)
11991205
XCTAssertEqual(effect.releasedCount, 1)

Tests/AtomsTests/Effect/InitializeEffectTests.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import XCTest
22

33
@testable import Atoms
44

5-
final class InitializeTests: XCTestCase {
5+
final class InitializeEffectTests: XCTestCase {
66
@MainActor
77
func testEvent() {
88
let context = AtomCurrentContext(store: .dummy)
@@ -11,6 +11,9 @@ final class InitializeTests: XCTestCase {
1111
performedCount += 1
1212
}
1313

14+
effect.initializing(context: context)
15+
XCTAssertEqual(performedCount, 0)
16+
1417
effect.initialized(context: context)
1518
XCTAssertEqual(performedCount, 1)
1619

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import XCTest
2+
3+
@testable import Atoms
4+
5+
final class InitializingEffectTests: XCTestCase {
6+
@MainActor
7+
func testEvent() {
8+
let context = AtomCurrentContext(store: .dummy)
9+
var performedCount = 0
10+
let effect = InitializingEffect {
11+
performedCount += 1
12+
}
13+
14+
effect.initializing(context: context)
15+
XCTAssertEqual(performedCount, 1)
16+
17+
effect.initialized(context: context)
18+
XCTAssertEqual(performedCount, 1)
19+
20+
effect.updated(context: context)
21+
XCTAssertEqual(performedCount, 1)
22+
23+
effect.released(context: context)
24+
XCTAssertEqual(performedCount, 1)
25+
}
26+
}

Tests/AtomsTests/Effect/ReleaseEffectTests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ final class ReleaseEffectTests: XCTestCase {
1111
performedCount += 1
1212
}
1313

14+
effect.initializing(context: context)
15+
XCTAssertEqual(performedCount, 0)
16+
1417
effect.initialized(context: context)
1518
XCTAssertEqual(performedCount, 0)
1619

0 commit comments

Comments
 (0)