Hi. I created a navigation in my application. However, when I try to modify the state within the view hierarchy, it does not work.
I created the simplest example I could, which shows the problem.
public enum Route: Hashable {
case sheet
case link
}
public struct AppState: Equatable {
@BindableState var route: Route?
public var myNumber: String = ""
public var myName: String = ""
public var sheetState: SheetState {
get {
.init(
myNumber: self.myNumber
)
}
set {
self.myNumber = newValue.myNumber
}
}
}
public enum AppAction: Equatable, BindableAction {
case sheetButtonTapped
case sheet(SheetAction)
case binding(BindingAction<AppState>)
}
public struct AppEnvironment { ยทยทยท }
public let appReducer = Reducer<AppState, AppAction, AppEnvironment>.combine(
sheetReducer.pullback(
state: \AppState.sheetState,
action: /AppAction.sheet,
environment: { _ in SheetEnvironment(mainQueue: .main) }
),
Reducer { state, action, environment in
switch action {
case .sheetButtonTapped:
state.route = .sheet
return .none
case .sheet(_):
return .none
case .binding(_):
return .none
}
}
.binding()
)
.debug()
struct AppView: View {
let store: Store<AppState, AppAction>
var body: some View {
WithViewStore(self.store) { viewStore in
VStack(alignment: .leading, spacing: 24) {
Text("Number: \(viewStore.myNumber)")
Text("Name: \(viewStore.myName)")
Button("Sheet") {
viewStore.send(.sheetButtonTapped, animation: .default)
}
.sheet(unwrapping: viewStore.binding(\.$route), case: /Route.sheet) { _ in
NavigationView {
SheetView(store: self.store.scope(
state: \.sheetState,
action: AppAction.sheet
))
}
}
}
}
}
}
public struct SheetState: Equatable {
@BindableState var myNumber: String = ""
public var name: String = ""
public var linkState: LinkState {
get {
.init(
name: self.name
)
}
set {
self.name = newValue.name
}
}
}
public enum SheetAction: Equatable, BindableAction {
case link(LinkAction)
case binding(BindingAction<SheetState>)
}
public struct SheetEnvironment { ยทยทยท }
public let sheetReducer = Reducer<SheetState, SheetAction, SheetEnvironment>.combine(
linkReducer.pullback(
state: \SheetState.linkState,
action: /SheetAction.link,
environment: { _ in LinkEnvironment(mainQueue: .main) }
),
Reducer { state, action, environment in
switch action {
case .binding(_):
return .none
case .link(_):
return .none
}
}.binding()
)
struct SheetView: View {
let store: Store<SheetState, SheetAction>
var body: some View {
WithViewStore(self.store) { viewStore in
VStack(alignment: .leading, spacing: 24) {
TextField("Type here the number...", text: viewStore.binding(\.$myNumber))
.keyboardType(.numberPad)
Text("The name is: \(viewStore.name)")
NavigationLink {
LinkView(store: self.store.scope(
state: \.linkState,
action: SheetAction.link
))
} label: {
Text("Push")
}.padding(.top, 44)
}
.padding(.horizontal, 20)
}
}
}
public struct LinkState: Equatable {
@BindableState var name: String = ""
}
public enum LinkAction: Equatable, BindableAction {
case binding(BindingAction<LinkState>)
}
public struct LinkEnvironment { ยทยทยท }
public let linkReducer = Reducer<LinkState, LinkAction, LinkEnvironment> { state, action, environment in
switch action {
case .binding(_):
return .none
}
}.binding()
.debug()
struct LinkView: View {
let store: Store<LinkState, LinkAction>
var body: some View {
WithViewStore(self.store) { viewStore in
TextField("Type here the name...", text: viewStore.binding(\.$name)) // It doesn't work
.padding(.horizontal, 20)
}
}
}
The binding in the LinkView doesn't work. The view is created again but I don't know why. What am I doing wrong?