I am trying to learn Swift and Composable Architecture, and I am following this tutorial. Now the above code works as expected, I having issue with showing different views in the same sheet. I have created another destination from LoginView
like below
struct LoginFeature: Reducer {
...
...
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .forgotPasswordButtonTapped:
state.destination = .forgotPassword(
ForgotPasswordFeature.State()
)
return .none
case .privacyPolicyButtonTapped:
state.destination = .privacyPolicy(
GeneralWebFeature.State(urlString: "<some link>")
)
return .none
...
...
}
and
extension LoginFeature {
struct Destination: Reducer {
enum State: Equatable {
case forgotPassword(ForgotPasswordFeature.State)
case privacyPolicy(GeneralWebFeature.State)
}
enum Action: Equatable {
case forgotPassword(ForgotPasswordFeature.Action)
case privacyPolicy(GeneralWebFeature.Action)
}
var body: some ReducerOf<Self> {
Scope(state: /State.forgotPassword, action: /Action.forgotPassword) {
ForgotPasswordFeature()
}
Scope(state: /State.privacyPolicy, action: /Action.privacyPolicy) {
GeneralWebFeature()
}
}
}
}
Now the problem is how to modify this sheet
to support multiple views since the state
and action
param does not support multiple actions, or this a wrong approach?
.sheet(
store: self.store.scope(
state: \.$destination,
action: { .destination($0) }
),
state: /LoginFeature.Destination.State.forgotPassword,
action: LoginFeature.Destination.Action.forgotPassword
) { forgotPasswordStore in
NavigationStack {
ForgotPasswordView(store: forgotPasswordStore)
}
}
Little help will be highly appreciated, thank you.
Add another sheet modifier to handle the privacyPolicy destination. See sample below:
import ComposableArchitecture
import SwiftUI
struct ViewFeature: Reducer {
struct State: Equatable {
@PresentationState var destination: Destination.State?
}
enum Action {
case showFirstSheetButtonTapped
case showSecondSheetButtonTapped
case destination(PresentationAction<Destination.Action>)
}
struct Destination: Reducer {
enum State: Equatable {
case firstSheet(String)
case secondSheet(String)
}
enum Action: Equatable {
case firstSheet(String)
case secondSheet(String)
}
var body: some ReducerOf<Self> {
Scope(
state: /ViewFeature.Destination.State.firstSheet,
action: /ViewFeature.Destination.Action.firstSheet
) {
EmptyReducer()
}
Scope(
state: /ViewFeature.Destination.State.secondSheet,
action: /ViewFeature.Destination.Action.secondSheet
) {
EmptyReducer()
}
}
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .showFirstSheetButtonTapped:
state.destination = .firstSheet("first sheet state")
return .none
case .showSecondSheetButtonTapped:
state.destination = .secondSheet("second sheet state")
return .none
case .destination:
return .none
}
}
.ifLet(\.$destination, action: /ViewFeature.Action.destination) {
Destination()
}
}
}
struct SampleView: View {
@State var store = Store(initialState: ViewFeature.State()) {
ViewFeature()
}
var body: some View {
WithViewStore(self.store, observe: { $0 }) { viewStore in
VStack {
Button("Show First Sheet") {
viewStore.send(.showFirstSheetButtonTapped)
}
Button("Show Second Sheet") {
viewStore.send(.showSecondSheetButtonTapped)
}
}
.sheet(
store: self.store.scope(
state: \.$destination,
action: ViewFeature.Action.destination
),
state: /ViewFeature.Destination.State.firstSheet,
action: { .firstSheet($0) }
) { firstSheetStore in
WithViewStore(firstSheetStore, observe: {$0}) {
Text($0.state)
}
}
.sheet(
store: self.store.scope(
state: \.$destination,
action: ViewFeature.Action.destination
),
state: /ViewFeature.Destination.State.secondSheet,
action: { .secondSheet($0) }
) { secondSheetStore in
WithViewStore(secondSheetStore, observe: {$0}) {
Text($0.state)
}
}
}
}
}
#Preview("Sample View") {
SampleView()
}