pointfreeco / swift-composable-architecture

A library for building applications in a consistent and understandable way, with composition, testing, and ergonomics in mind.
https://www.pointfree.co/collections/composable-architecture
MIT License
12.24k stars 1.42k forks source link

Issue using with Stepper #224

Closed karthikgs7 closed 4 years ago

karthikgs7 commented 4 years ago

Describe the bug After couple of actions, one of the buttons got disabled, and tapping on the other button sends the invalid action to the store.

To Reproduce Try copy-pasting the code in SwiftUI file, run and do couple of actions with the stepper.

import SwiftUI
import ComposableArchitecture

struct CounterState: Equatable {
    var title: String = ""
    var count: Int = 0
}

enum CounterAction: Equatable {
    case incrementCountTapped
    case decrementCountTapped
}

struct CounterEnvironment {}

let counterReducer = Reducer<CounterState, CounterAction, CounterEnvironment> { state, action, environment in
    switch action {
    case .incrementCountTapped:
        state.count += 1
        return .none
    case .decrementCountTapped:
        state.count -= 1
        return .none
    }
}

struct CounterView: View {

    let store: Store<CounterState, CounterAction>

    var body: some View {
        WithViewStore(self.store) { viewStore in
            HStack {
                Text("Count")
                Stepper(onIncrement: {
                    viewStore.send(.incrementCountTapped)
                }, onDecrement: {
                    viewStore.send(.decrementCountTapped)
                }, label: {
                    Text("\(viewStore.count)")
                })
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        CounterView(
            store: Store(
                initialState: CounterState(),
                reducer: counterReducer,
                environment: CounterEnvironment()
            )
        )
    }
}

Expected behavior Tapping on the button should be changing the value without disabling the UI elements.

Screenshots screenshot

Environment

mbrandonw commented 4 years ago

Hey @karthikgs7, thanks for the report!

We've actually stumbled upon this before, and we've gotten some confirmation from Apple that this is most likely a SwiftUI bug. We documented this on the WithViewStore type:

https://github.com/pointfreeco/swift-composable-architecture/blob/c9c1a9a50040408c436e496bac35007add327186/Sources/ComposableArchitecture/SwiftUI/WithViewStore.swift#L15-L18

To work around can you use the version of Stepper that takes a binding instead? You will need to manually check the before and after value in the reducer to determine if the value was incremented or decremented.

mbrandonw commented 4 years ago

Gonna close this issue for now, but please feel free to reopen if you have more questions!