Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

View not updating when associated values of enum States are modified #2990

Closed
1 of 3 tasks
funct7 opened this issue Apr 15, 2024 · 4 comments
Closed
1 of 3 tasks

View not updating when associated values of enum States are modified #2990

funct7 opened this issue Apr 15, 2024 · 4 comments
Labels
bug Something isn't working due to a bug in the library.

Comments

@funct7
Copy link

funct7 commented Apr 15, 2024

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 main branch of this package.
  • 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
@funct7 funct7 added the bug Something isn't working due to a bug in the library. label Apr 15, 2024
@mbrandonw
Copy link
Member

Hi @funct7, your code seems to run perfectly fine for me. What problem are you seeing?

enum-state.mov

For what it's worth, the fix I alluded to in that discussion was PR'd here #2786 and merged.

@funct7
Copy link
Author

funct7 commented Apr 17, 2024

Are you on 1.9.2? Not sure if I'm doing something wrong here, but it's not working properly for me...

Screen.Recording.2024-04-17.at.4.19.53.PM.mov

@mbrandonw
Copy link
Member

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 #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.

@mbrandonw
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working due to a bug in the library.
Projects
None yet
Development

No branches or pull requests

2 participants