I am experimenting a bit around SwiftUI and trying to understand SwiftUI's @State behavior. I found myself preparing a component that has a @State of its own. Something like the below code snippet:
Code
I am displaying 4 WrappedTextField views in a VStack, data populated from an @Published list in the view model. There is a delete button(x) attached with all the views. On pressing the delete button, I am removing the data at that index from the data source.
struct WrappedTextField: View {
@State var text: String
var body: some View {
Text(text)
}
}
class ExperimentViewModel: ObservableObject {
@Published var dataSource = ["0", "1", "2", "3"]
func remove(at index: Int) {
guard index < dataSource.count else {
return
}
dataSource.remove(at: index)
}
}
struct ExperimentView: View {
@ObservedObject var viewModel: ExperimentViewModel = ExperimentViewModel()
var body: some View {
VStack {
ForEach(0..<viewModel.dataSource.count, id: \.self) { index in
HStack {
WrappedTextField(text: viewModel.dataSource[index])
Button(action: {
viewModel.remove(at: index)
}, label: {
Text("x").foregroundColor(.red)
})
}
}
}
}
}
Expected Behaviour
Ideally, the view should reflect the alteration and remove the WrappedTextField at that particular index.
Behaviour
As shown below, on deleting an index in the data source, it deletes it but the WrappedTextField still retains the previous values.
My understanding
My understanding is that somehow the @State of the particular WrappedTextField has not been updated after the delete.
Approaches that work.
If we remove the @State inside the WrappedTextField, the code will work as expected.
Question
I am still trying to figure out what is the exact reason for this behavior. What is the reason that @State is getting retained with previous values even though the data source has been changed?
