You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/docs/brownie/swift-usage.mdx
+79-44Lines changed: 79 additions & 44 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -44,77 +44,100 @@ struct MyApp: App {
44
44
45
45
### @UseStore Property Wrapper
46
46
47
-
The `@UseStore` property wrapper provides reactive access to the store:
47
+
The `@UseStore` property wrapper provides reactive access to a selected slice of state using KeyPath selectors. This ensures your view only re-renders when the selected value changes.
48
48
49
49
```swift
50
50
importBrownie
51
51
importSwiftUI
52
52
53
-
structContentView: View {
54
-
@UseStore<BrownfieldStore>varstore
53
+
structCounterView: View {
54
+
@UseStore(\BrownfieldStore.counter)varcounter
55
55
56
56
var body: some View {
57
57
VStack {
58
-
Text("Count: \(Int(store.state.counter))")
58
+
Text("Count: \(Int(counter))")
59
59
60
60
Button("Increment") {
61
-
store.set { $0.counter+=1 }
61
+
$counter.set { $0+1 }
62
62
}
63
63
}
64
64
}
65
65
}
66
66
```
67
67
68
+
### Selectors
69
+
70
+
Every `@UseStore` requires a KeyPath selector. This:
71
+
72
+
- Forces explicit state selection
73
+
- Prevents unnecessary re-renders (only updates when selected value changes)
74
+
- Provides type-safe access to state
75
+
76
+
```swift
77
+
// Select primitive
78
+
@UseStore(\BrownfieldStore.counter) var counter // counter is Double
79
+
80
+
// Select nested object
81
+
@UseStore(\BrownfieldStore.user) var user // user is User
82
+
```
83
+
84
+
:::info Equatable Requirement
85
+
Selected values must conform to `Equatable` for change detection. Add `Equatable` to your generated types.
86
+
:::
87
+
68
88
### Updating State
69
89
70
-
Use the `set` method with a closure to mutate state:
90
+
Use the projected value (`$`) to access setter methods:
71
91
72
92
```swift
73
-
//Update single property
74
-
store.set { $0.counter+=1 }
93
+
//Set value directly
94
+
$counter.set(10)
75
95
76
-
//Update nested property
77
-
store.set { $0.user.name="John" }
96
+
//Set with closure (receives current value)
97
+
$counter.set { $0+1 }
78
98
79
-
// Update multiple properties
80
-
store.set {
81
-
$0.counter=0
82
-
$0.user.name="Reset"
83
-
}
99
+
// For nested types, replace the whole object
100
+
$user.set(User(name: "John"))
84
101
```
85
102
86
-
### TextField Binding
103
+
### Multiple Selectors
87
104
88
-
For two-way binding with TextField, create a `Binding`:
105
+
Use multiple `@UseStore` declarations for different state slices. Each only triggers re-renders when its selected value changes:
89
106
90
107
```swift
91
-
structContentView: View {
92
-
@UseStore<BrownfieldStore>var store
108
+
structMyView: View {
109
+
@UseStore(\BrownfieldStore.counter) var counter
110
+
@UseStore(\BrownfieldStore.user) var user
93
111
94
112
var body: some View {
95
-
TextField("Name", text: Binding(
96
-
get: { store.state.user.name },
97
-
set: { store.set { $0.user.name=$0 } }
98
-
))
99
-
.textFieldStyle(.roundedBorder)
113
+
VStack {
114
+
Text("Count: \(Int(counter))")
115
+
Text("User: \(user.name)")
116
+
117
+
Button("Increment") {
118
+
$counter.set { $0+1 }
119
+
}
120
+
}
100
121
}
101
122
}
102
123
```
103
124
104
-
### Reading State
125
+
### TextField Binding
105
126
106
-
Access state via the `state` property or keypaths:
127
+
For two-way binding with TextField, create a `Binding`:
0 commit comments