Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Enum reducer and .sheet(item:onDismiss:content:): Make cases have different ID #3678

Unanswered
jessedoescode asked this question in Q&A
Discussion options

Hey! Apple's docs on sheet(item:onDismiss:content:) state on the item:

If item changes, the system dismisses the sheet and replaces it with a new one using the same process.

However, if I'm doing:

@Reducer(state: .equatable)
    enum Sheet {
        case featureA(FeatureA)
        case featureB(FeatureB)
    }

sheet(item: $store.scope(state: \.sheet, action: \.sheet)) { store in
            let _ = print("createMenuSheet", store.id)
            switch store.case {
            case let .featureA(store):
                FeatureA(store: store)
            case let .featureB(store):
                FeatureB(store: store)

SwiftUI won't recognize a change to the enum case and won't animate the sheet disappearing and reappearing with the new content, as the id handled by scoped store remains the same? Or have I omitted something. The behaviour I'm seeing is that the sheet content does change, but the sheet does not dismiss and reappear, but instead stays open constantly.

Thank you!

You must be logged in to vote

Replies: 1 comment · 3 replies

Comment options

This seems like the expected behaviour to me - you're using a single .sheet modifier with an item that is the store scoped to the sheet value. Try using two .sheet modifiers with each scoped to the appropriate case instead (e.g. state: \.sheet?.featureA, action: .sheet.featureA)`).

You must be logged in to vote
3 replies
@jessedoescode
Comment options

@lukeredpath Thanks! When using a bare enum conforming to Identifiable, SwiftUI does animate sheet dismissal and reappear on case change, even when using a single .sheet modifier, so I was wondering.

enum State: String, Identifiable {
    case featureA = "A"
    case featureB = "B"
    
    var id: String {
        self.rawValue
    }
}

.sheet(item: $state) { state in
                switch state {
                case .featureA:
                    Text("Feature A")
                case .featureB:
                    Text("Feature B")
                }
            }

But using multiple .sheet modifiers is a valid workaround 👍

@lukeredpath
Comment options

Yes, this will work but its very different to passing in a reference to a store - in your second example $state is a binding to a value so SwiftUI can easily tell when its value has changed, where as in the first example the item will always be a Store<Sheet.State?, Sheet.Action>. Perhaps it would be possible for the store to derive a unique ID when its State conforms to identifiable, I don't know.

@mbrandonw
Comment options

We do have a PR to derive store identity from the state's identity: #3464. But more needs to be explored before that can be ready to merge.

Until then you can always conform Sheet.State to be identifiable and then use the sheet(item:id:) method that comes with SwiftUINavigation (which is included in TCA automatically):

extension Sheet.State: Identifiable {
  var id: AnyHashable {  }
}

// in the view:
.sheet(item: $store.scope(state: \.sheet, action: \.sheet), id: \.id) { store in
  
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
🙏
Q&A
Labels
None yet
3 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.