Hi, I was taught that:
- if my SwiftUI view changes data that are kept outside of the view, it should use
@Binding - if my view keeps its state in some variables, the variables should be
@State - if my view only receives data to present etc. then the fields should be normal fields (
let xyz: String)
In my case I should use the last option because my view only presents the data, but my question/problem is how to pass the current, up to date data to the view's StateObject? Setting the values for the StateObject in onAppear is not the proper way to solve the problem. For example:
// --- Main view ---
class MainViewModel: ObservableObject {
@Published var items = [Int]()
// ... logic
}
struct MainView: View {
@StateObject var mainViewModel = MainViewModel()
var body: some View {
// 1
MyView(items: mainViewModel.items)
}
}
// --- My view ---
struct MyView: View {
let items: [Int]
var body: some View {
// 2
MyViewSubview(items: items)
}
}
// --- My view's subview
class MyViewSubviewModel: ObservableObject {
@Published var itemsPresentation = ""
func prepareItemsForPresentation(items: [Int]) {
// ... logic
}
}
struct MyViewSubview: View {
let items: [Int]
@StateObject private var myViewSubviewModel = MyViewSubviewModel()
init(items: [Int]) {
self.items = items
}
var body: some View {
// 4
Text(myViewSubviewModel.itemsPresentation)
.onAppear {
// 3
myViewSubviewModel.prepareItemsForPresentation(items: items)
}
}
}
When mainViewModel.items changes (1) it will update and redraw MyView (👍).
In MyView, updated items will go to MyViewSubview (2) and cause update and redraw (👍).
The problem is happening here in MyViewSubview, we need to update the delivered data, the proper way is to do it in onAppear (3) BUT it will be called only once - when the view is presented the first time. The subsequent updates of items and redraws of the MyViewSubview will not call prepareItemsForPresentation and so it will not call the login in MyViewSubviewModel and it will not present the proper data (4).
How to refresh/update @StateObject whenever new data is passed through an initializer of a view??? onChange(of:perform:) doesn't work, because items is not a @State variable (and can't be, because I shouldn't set @State in an initializer).