Jan 8, 2024
Present an alert using TCA
Alert with custom actions
Here's how you can present a SwiftUI alert using the Composable Architecture.
import ComposableArchitecture import SwiftUI @Reducer struct ShowAlertFeature { @ObservableState struct State: Equatable { @Presents var alert: AlertState<Action.Alert>? } enum Action: BindableAction { enum Alert { case tappedRetry } case alert(PresentationAction<Alert>) case binding(BindingAction<State>) case showAlert } var body: some Reducer<State, Action> { BindingReducer() Reduce { state, action in switch action { case .alert(.presented(.tappedRetry)): // Execute logic return .none case .showAlert: // Showing an alert state.alert = AlertState { TextState("Could not load") } actions: { // This will dismiss the alert ButtonState(role: .cancel) { TextState("OK") } ButtonState(action: .tappedRetry) { TextState("Retry") } } message: { TextState("Alert message") } return .none case .alert, .binding: return .none } } .ifLet(\.$alert, action: \.alert) } } struct ShowAlertView: View { @Bindable var store: StoreOf<ShowAlertFeature> var body: some View { VStack { } .alert($store.scope(state: \.alert, action: \.alert)) } }
Alert without custom actions
Here's how you can show a SwiftUI alert without custom action buttons using the Composable Architecture.
import ComposableArchitecture import SwiftUI @Reducer struct ShowNoActionAlertFeature { @ObservableState struct State: Equatable { @Presents var alert: AlertState<Never>? } enum Action: BindableAction { case alert(PresentationAction<Never>) case binding(BindingAction<State>) case showAlert } var body: some Reducer<State, Action> { BindingReducer() Reduce { state, action in switch action { case .showAlert: state.alert = AlertState { TextState("Could not load") } actions: { // This will dismiss the alert ButtonState(role: .cancel) { TextState("OK") } } message: { TextState("Alert message") } return .none case .alert, .binding: return .none } } .ifLet(\.$alert, action: \.alert) } } struct ShowNoActionAlertView: View { @Bindable var store: StoreOf<ShowNoActionAlertFeature> var body: some View { VStack { Button("Show Alert") { store.send(.showAlert) } } .alert($store.scope(state: \.alert, action: \.alert)) } }