I have the following NewCategoryView view:
struct NewCategoryView: View {
/// Store
let store: Store<NewCategoryState, NewCategoryAction>
/// ViewStore
@ObservedObject var viewStore: ViewStore<NewCategoryState, NewCategoryAction>
init() {
self.store = Store(
initialState: NewCategoryState(),
reducer: newCategoryReducer,
environment: { }())
self.viewStore = ViewStore(self.store)
}
var body: some View {
NavigationView {
VStack(alignment: .leading, spacing: 16) {
// ...
IconList
}
// ...
}
}
var IconList: some View {
let rows: Int
if icons.count % 6 != 0 {
rows = (icons.count / 6) + 1
} else {
rows = (icons.count / 6)
}
return VStack(alignment: .leading, spacing: 8) {
Group {
Text("Icon")
//.primaryLabel()
.padding(.horizontal)
Text("Wähle ein Icon aus")
//.primaryInfoLabel()
.padding(.horizontal)
}.resignKeyboardOnDragGesture()
ScrollView(.horizontal, showsIndicators: false) {
ForEach(0..<6) { y in
HStack(alignment: .center, spacing: 8) {
ForEach(0..<rows) { x in
IconButton(
index: x * 6 + y,
selectedIcon:
// THIS DOES NOT WORK?
self.viewStore.binding(
get: { $0.selectedIcon },
send: NewCategoryAction.selectedIconChanged
).debug("IconButton")
)
}
}.padding(.horizontal)
}.padding(.vertical, 2)
}
}
}
and I want to bind a value from the store to this next IconButton view:
struct IconButton: View {
/// The index in the icon list (String)
let index: Int
/// The name of the selected icon
@Binding var selectedIcon: String
var body: some View {
if index < icons.count {
let icon: String = icons[index]
return Button(action: {
self.selectedIcon = icon
}) {
Image(systemName: icon)
.foregroundColor(.label)
.frame(width: 69, height: 50)
//.background(Color.tertiarySystemFill)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(Color.blue, lineWidth: icon == selectedIcon ? 4 : 0)
)
.cornerRadius(8)
}.eraseToAnyView()
} else {
return
Spacer()
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 50, maxHeight: 50)
.eraseToAnyView()
}
}
}
public let icons = ["airplane",
"alarm",
"antenna.radiowaves.left.and.right",
"app.gift.fill",
"archivebox.fill" //...
]
The NewCategoryCore:
public enum NewCategoryViewAlert: Int, Identifiable {
case name = 0
case icon = 1
var text: String {
switch self {
case .name:
return "Lege einen Namen fest!"
case .icon:
return "Wähle ein Icon aus!"
}
}
public var id: Int {
return self.rawValue
}
}
public struct NewCategoryState: Equatable {
/// The name of the selected icon
var selectedIcon: String = ""
/// The name of the new category
var categoryName: String = ""
/// The alert of the view
var alert: NewCategoryViewAlert?
}
enum NewCategoryAction: Equatable {
case saveSpace
case categoryNameChanged(String)
case selectedIconChanged(String)
case alertChanged(NewCategoryViewAlert?)
}
let newCategoryReducer = Reducer<NewCategoryState, NewCategoryAction, Void> { state, action, _ in
switch action {
case .saveSpace:
// MARK: TODO save
return .none
case let .categoryNameChanged(name):
state.categoryName = name
return .none
case let .selectedIconChanged(icon):
state.selectedIcon = icon
return .none
case let .alertChanged(alert):
state.alert = alert
return .none
}
}.debug()
In the console this seams to work:
IconButton: setting bandage.fill to calendar
received action:
NewCategoryAction.selectedIconChanged(
"calendar"
)
NewCategoryState(
− selectedIcon: "bandage.fill",
+ selectedIcon: "calendar",
categoryName: "",
alert: nil
)
... but the IconButton view does not update.
What am I missing?
I'm sorry for my bad english.