@Bindable state question #1511
Replies: 1 comment 1 reply
-
Bindable state is not capable of being passed around like this: state.gameFeature = .init(isPresented: state.$isPresented) If you mutate This is because bindable state has two parts to its implementation: the part in the reducer for updating state, and the part in the view for sending actions (which is the binding). By passing But, I think there is a better way to deal the navigation you are trying to accomplish. You shouldn't model your domain as a boolean and an optional. That allows for non-sensical states such as Instead, you can ditch the boolean entirely, and only use the optional to drive presenting/dismissing the fullscreen cover. You can even use Here is the code that does that: public struct HomeFeature: ReducerProtocol {
public init() {}
public struct State: Equatable {
var gameFeature: GameFeature.State? = nil
public init() {}
}
public enum Action: Equatable {
case dismissGame
case gameFeature(GameFeature.Action)
case openButtonTapped
}
public var body: some ReducerProtocol<State, Action> {
CombineReducers {
Reduce(self.core)
.ifLet(\.gameFeature, action: /Action.gameFeature) {
GameFeature()
}
}
}
func core(state: inout State, action: Action) -> Effect<Action, Never> {
switch action {
case .dismissGame:
state.gameFeature = nil
return .none
case .gameFeature:
return .none
case .openButtonTapped:
state.gameFeature = .init()
return .none
}
}
}
public struct HomeView: View {
var store: StoreOf<HomeFeature>
public init(store: StoreOf<HomeFeature>) {
self.store = store
}
public var body: some View {
// Note we are being specific about what to observe here:
WithViewStore(self.store, observe: \.gameFeature) { viewStore in
Button {
viewStore.send(.openButtonTapped)
} label: {
Text("Open child view")
}
.fullScreenCover(
isPresented: viewStore.binding(get: { $0 != nil }, send: { _ in .dismissGame })
) {
IfLetStore(
self.store.scope(
state: { $0.gameFeature },
action: HomeFeature.Action.gameFeature
)
) { childStore in
GameView(store: childStore)
}
}
}
}
}
public struct GameFeature: ReducerProtocol {
public init() {}
public struct State: Equatable {}
public enum Action: Equatable {}
public var body: some ReducerProtocol<State, Action> {
Reduce(self.core)
}
func core(state: inout State, action: Action) -> Effect<Action, Never> {}
}
struct GameView: View {
@Environment(\.dismiss) var dismss
let store: StoreOf<GameFeature>
var body: some View {
VStack {
Text("Game")
Button {
self.dismss()
} label: {
Text("Close")
}
}
}
} |
Beta Was this translation helpful? Give feedback.
-
I have a parent view
HomeFeature
with some bindable stateIn my
HomeView
I want to present myGameView
usingIfLetStore
and the@BindableState var isPresented
The
GameFeature
is initialized with the@BindableState var isPresented
I can see that my
state.gameFeature
is set to nil but this results in the IfLetStoreelseContent:
being rendered as an empty white screen instead of just dismissing the view? I dont have an else clause definedBeta Was this translation helpful? Give feedback.
All reactions