swift-composable-architecture
                                
                                 swift-composable-architecture copied to clipboard
                                
                                    swift-composable-architecture copied to clipboard
                            
                            
                            
                        View not updating when associated values of enum States are modified
Description
When you use an enum type for State, views aren't updated for changes in the associated value.
A discussion has been opened #2778, but it seems like fixes are yet to come. I'm creating this issue since I find this a major issue, but the discussion doesn't seem to give it much visibility.
I personally find this a major issue, since states, especially for declarative UIs, are much more unambiguous using sum types instead of product types.
For example:
enum State {
    case idle(Int)
    case loading(Int)
    case loaded(Int, String)
}
is much better than
struct State {
    var count = 0
    var fact: String?
    var isLoading = false
}
as it precludes the possibility of states that shouldn't exist such as
State(count: 1, fact: "foo", isLoading: true)
I remember this working in v1.0.0, but it has stopped working at some version along the way.
Checklist
- [ ] I have determined whether this bug is also reproducible in a vanilla SwiftUI project.
- [ ] If possible, I've reproduced the issue using the mainbranch of this package.
- [X] This issue hasn't been addressed in an existing GitHub issue or discussion.
Expected behavior
Views should change when associated values of cases change.
Actual behavior
Views aren't changing for changes in associated values, but only for case changes.
Steps to reproduce
The following code demonstrates this:
@Reducer
struct DemoFeature {
    
    @ObservableState
    enum State {
        case zero
        case nonZero(Int)
        
        var value: Int {
            get {
                switch self {
                case .zero: 0
                case .nonZero(let value): value
                }
            }
            set {
                self = newValue == 0 ? .zero : .nonZero(newValue)
            }
        }
    }
    
    enum Action : Equatable {
        case didTapIncrement
        case didTapDecrement
        case didTapReset
    }
    
    var body: some ReducerOf<Self> {
        Reduce { state, action in
            switch action {
            case .didTapDecrement: state.value -= 1
            case .didTapIncrement: state.value += 1
            case .didTapReset: state = .zero
            }
            
            return .none
        }
    }
    
}
struct DemoView : View {
    
    let store: StoreOf<DemoFeature>
    
    var body: some View {
        VStack {
            Text("\(store.value)")
                .font(.largeTitle)
                .padding()
                .background(.black.opacity(0.1))
                .cornerRadius(10)
            
            HStack {
                Button("-") {
                    store.send(.didTapDecrement)
                }
                .font(.largeTitle)
                .padding()
                .background(.black.opacity(0.1))
                .cornerRadius(10)
                
                Button("+") {
                    store.send(.didTapIncrement)
                }
                .font(.largeTitle)
                .padding()
                .background(.black.opacity(0.1))
                .cornerRadius(10)
            }
            
            Button("Reset") {
                store.send(.didTapReset)
            }
            .font(.largeTitle)
            .padding()
            .background(.black.opacity(0.1))
            .cornerRadius(10)
        }
    }
    
}
#Preview("Demo") {
    DemoView(store: Store(initialState: .zero) {
        DemoFeature()
    })
}
The Composable Architecture version information
1.9.2
Destination operating system
iOS 17
Xcode version information
15.0.1
Swift Compiler version information
swift-driver version: 1.87.1 Apple Swift version 5.9 (swiftlang-5.9.0.128.108 clang-1500.0.40.1)
Target: arm64-apple-macosx14.0
Hi @funct7, your code seems to run perfectly fine for me. What problem are you seeing?
https://github.com/pointfreeco/swift-composable-architecture/assets/135203/43ba3737-de1b-443e-beff-4446c2ff328b
For what it's worth, the fix I alluded to in that discussion was PR'd here #2786 and merged.
Are you on 1.9.2? Not sure if I'm doing something wrong here, but it's not working properly for me...
https://github.com/pointfreeco/swift-composable-architecture/assets/12147008/c2e77a02-4e04-4dbd-bf19-a82c02d7067e
Hi @funct7, sorry I was testing on main because I didn't think it had deviated much from 1.9.2. Turns out the PR that made the fix was actually this one https://github.com/pointfreeco/swift-composable-architecture/pull/2910, and looks like that was merged just a few days after 1.9.2.
We'll get a release out soon and then it will be officially fixed.
Hi @funct7, this should be fixed with the latest release, 1.9.3, and so I am going to close this for now. Let us know if there are any other problems.