Quinn
Quinn

Reputation: 9476

Modifying a @State var from a @Binding var isn't refreshing the view in SwiftUI

So I have a ParentView which contains a FilterBar and a List. It looks something like this:

struct ParentView: View {
    @State var listCellModels: [ListCellModel]

    // Both these vars are passed to the FilterBar and adjusted by the FilterBar
    @State var isEditing: Bool = false
    @State var selectedType: FilterType = .none

    // When selected type is changed, I need to reload the models in the list with the new filter
    private var filteredModels: [ListCellModel] {
        return listCellModels.filter{
            (selectedType.rawValue == 0 || $0.approved.rawValue == selectedType.rawValue)
        }
    }

    var body: some View {
        VStack {
            FilterBar(isEditing: $isEditing, selectedType: $selectedType)

            // All the items in the list are buttons that display a custom view I had
            // this works fine, and when isEditing is changed the view DOES update
            List(filteredModels) { model in
                Button(action: {
                    // Does a thing
                }, label: {
                    ListViewCell(model: model, isEditing: self.$isEditing)
                })
            }
        }
    }
}

My Filter bar is just a simple HStack with a couple buttons that modify the variables

struct FilterBar: View {
    @Binding var isEditing: Bool
    @Binding var selectedType: FilterType

    var body: some View {
        HStack(alignment: .center) {
            Button(action: {
                self.selectedType = FilterType.init(rawValue: (self.selectedType.rawValue + 1) % 4)!
            }, label: {
                Text("Filter: \(selectedType.name)")
            }).padding(.top).padding(.leading)

            Spacer()

            Button(action: {
                self.isEditing = !self.isEditing
            }, label: {
                Text(!isEditing ? "Edit" : "Done")
            }).padding(.top).padding(.trailing)
        }
    }
}

When I tap the button that changes isEditing, all of the cells in the list update to show their "Editing" states, but when i tap the button to change selectedType, the variable in the parent view does get updated, as I've observed in the debugger - however the view does not reload. So it appears as if the old filter is still being applied.

Is there any reason why updating this @State var is not reloading the view?

Are there any workarounds?

Upvotes: 2

Views: 1048

Answers (1)

Asperi
Asperi

Reputation: 258385

Well, it is like... workaround... but for testing, try

FilterBar(isEditing: $isEditing, selectedType: $selectedType)
if selectedType != .none {
   EmptyView()
}

In general, it would be correct to introduce view model as ObservableObject and have filteredModels in it as @Published, so your FilterBar changed that property, which will automatically refreshed the ParentView.

Upvotes: 3

Related Questions