0

In the following example, I have an ObservableObject which holds a list of Floor, a view that renders the floor list, and a button that update the list when clicked.

I expect that when button is clicked, the view will update from "ABC" to "XYC", however, it won't update at all.

struct Floor: Identifiable {
    let id: Int
    let content: String
}

class ViewModel: ObservableObject {
    @Published var floors = [
        Floor(id: 1, content: "A"),
        Floor(id: 2, content: "B"),
        Floor(id: 3, content: "C")
    ]
    
    func alter() {
        floors[0...1] = [
            Floor(id: 1, content: "X"),
            Floor(id: 2, content: "Y"),
        ]
    }
}

struct ListBlock: View {
    @State var floor: Floor
  
    // floor may be updated from within
    
    var body: some View {
        Text(floor.content)
    }
}

struct ListView: View {
    @ObservedObject var vm = ViewModel()

    var body: some View {
        List {
            Button("Alter") {
                vm.alter()
            }
            
            ForEach(vm.floors) { floor in
                ListBlock(floor: floor)
            }
        }
    }
}

I'm wondering whether there is a way for me to update the view when the underlying data changes?

Note: I use @State in ListBlock as I may update the floor from within the ListBlock view.

0

1 Answer 1

1

To change the data from the Childview change that wrapper to a @Binding. Pass that on with the $ syntax. Also if you create your ViewModel you should wrap it in an @StateObject wrapper.

struct ListBlock: View {
    // add a binding here if you want to alter the content
    @Binding var floor: Floor
  
    // floor may be updated from within
    
    var body: some View {
        Text(floor.content)
    }
}

struct ListView: View {
    // If you initialize and hold the viewmodel here use @StateObject
    @StateObject private var vm = ViewModel()

    var body: some View {
        List {
            Button("Alter") {
                vm.alter()
            }
            
            // use the binding syntax here to propagate changes in the child to the parent
            ForEach($vm.floors) { $floor in
                ListBlock(floor: $floor)
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.