Skip to content

Commit b091bd7

Browse files
Basics of composition in the "essentials" tutorial (#2659)
* New tutorial section for composing features. * wip * wip * wip * wip * wip * wip * fix --------- Co-authored-by: Stephen Celis <[email protected]>
1 parent 6f1e023 commit b091bd7

25 files changed

+606
-5
lines changed

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,28 @@ case .startButtonTapped:
508508
This greatly reduces the bandwidth of actions being sent into the system so that you are not
509509
incurring unnecessary costs for sending actions.
510510

511+
Another example that comes up often is sliders. If done in the most direct way, by deriving a
512+
binding from the view store to hand to a `Slider`:
513+
514+
```swift
515+
Slider(value: viewStore.$opacity, in: 0...1)
516+
```
517+
518+
This will send an action into the system for every little change to the slider, which can be dozens
519+
or hundreds of actions as the user is dragging the slider. If this turns out to be problematic then
520+
you can consider alternatives.
521+
522+
For example, you can hold onto some local `@State` in the view for using with the `Slider`, and
523+
then you can use the trailing `onEditingChanged` closure to send an action to the store:
524+
525+
```swift
526+
Slider(value: self.$opacity, in: 0...1) {
527+
self.store.send(.setOpacity(self.opacity))
528+
}
529+
```
530+
531+
This way an action is only sent once the user stops moving the slider.
532+
511533
### Compiler performance
512534

513535
In very large SwiftUI applications you may experience degraded compiler performance causing long
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import SwiftUI
2+
3+
struct AppView: View {
4+
var body: some View {
5+
TabView {
6+
7+
}
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import SwiftUI
2+
3+
struct AppView: View {
4+
var body: some View {
5+
TabView {
6+
CounterView(store: ???)
7+
.tabItem {
8+
Text("Counter 1")
9+
}
10+
11+
CounterView(store: ???)
12+
.tabItem {
13+
Text("Counter 2")
14+
}
15+
}
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import ComposableArchitecture
2+
import SwiftUI
3+
4+
struct AppView: View {
5+
let store1: StoreOf<CounterFeature>
6+
let store2: StoreOf<CounterFeature>
7+
8+
var body: some View {
9+
TabView {
10+
CounterView(store: store1)
11+
.tabItem {
12+
Text("Counter 1")
13+
}
14+
15+
CounterView(store: store2)
16+
.tabItem {
17+
Text("Counter 2")
18+
}
19+
}
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import ComposableArchitecture
2+
3+
@Reducer
4+
struct AppFeature {
5+
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import ComposableArchitecture
2+
3+
@Reducer
4+
struct AppFeature {
5+
struct State {
6+
var tab1 = CounterFeature.State()
7+
var tab2 = CounterFeature.State()
8+
}
9+
enum Action {
10+
case tab1(CounterFeature.Action)
11+
case tab2(CounterFeature.Action)
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import ComposableArchitecture
2+
3+
@Reducer
4+
struct AppFeature {
5+
struct State {
6+
var tab1 = CounterFeature.State()
7+
var tab2 = CounterFeature.State()
8+
}
9+
enum Action {
10+
case tab1(CounterFeature.Action)
11+
case tab2(CounterFeature.Action)
12+
}
13+
var body: some ReducerOf<Self> {
14+
Reduce { state, action in
15+
// Core logic of the app feature
16+
return .none
17+
}
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import ComposableArchitecture
2+
3+
@Reducer
4+
struct AppFeature {
5+
struct State {
6+
var tab1 = CounterFeature.State()
7+
var tab2 = CounterFeature.State()
8+
}
9+
enum Action {
10+
case tab1(CounterFeature.Action)
11+
case tab2(CounterFeature.Action)
12+
}
13+
var body: some ReducerOf<Self> {
14+
Scope(state: \.tab1, action: \.tab1) {
15+
CounterFeature()
16+
}
17+
Scope(state: \.tab2, action: \.tab2) {
18+
CounterFeature()
19+
}
20+
Reduce { state, action in
21+
// Core logic of the app feature
22+
return .none
23+
}
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import ComposableArchitecture
2+
import XCTest
3+
4+
class AppFeatureTests: XCTestCase {
5+
func testIncrementInFirstTab() {
6+
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import ComposableArchitecture
2+
import XCTest
3+
4+
class AppFeatureTests: XCTestCase {
5+
func testIncrementInFirstTab() {
6+
let store = TestStore(initialState: AppFeature.State()) {
7+
AppFeature()
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)