I have a question according to the function of the @Observable
-macro:
I am using an @Observable object as a source of truth in my view. My class
has an array, but I would like to reorganize this data in my view. I was asking myself, what would be the best way to do that and I came up with the idea of using a computed property:
@Observable
class MyObservable {
var items = [0, 1, 2, 3, 4]
}
struct TestView: View {
var myObservable = MyObservable()
var filtered: [Int] {
myObservable.items.filter { $0 % 2 == 0 }
}
var body: some View {
VStack(alignment: .leading) {
Text("\(filtered)")
}
}
}
This works as pretended. But I was asking myself: Will this view be re-rendered, when any other property in the class will be changed?
I tested it like this:
@Observable
class MyObservable {
var items = [0, 1, 2, 3, 4]
var temp = 1
}
struct TestView: View {
var myObservable = MyObservable()
var filtered: [Int] {
print("rerenderred")
return myObservable.items.filter { $0 % 2 == 0 }
}
var body: some View {
VStack(alignment: .leading) {
Text("\(filtered)")
Text("\(myObservable.temp)")
Button("Increase Counter") {
// question: does this lead to a re-render?
myObservable.temp += 1
}
Button("test") {
// this of course will lead to a re-render
myObservable.items.append(myObservable.items.last!+1)
}
}
}
}
Unfortunately, every time I press the button "Increase counter", I get the print "rerendered". So the computed property will be calculated again, altough the property items
will not be changed after clicking the button.
I guess I could change this behaviour by using .onChange(of: myObservable.items ...
?
The other idea is to take out the computed property to another view:
@Observable
class MyObservable {
var items = [0, 1, 2, 3, 4]
var temp = 1
}
struct TmpView: View {
var myObservable: MyObservable
var filtered: [Int] {
print("rerenderred")
return myObservable.items.filter { $0 % 2 == 0 }
}
var body: some View {
Text("\(filtered)")
}
}
struct TestView: View {
var myObservable = MyObservable()
var body: some View {
VStack(alignment: .leading) {
TmpView(myObservable: myObservable)
Text("\(myObservable.temp)")
Button("Increase Counter") {
// this does NOT lead to a re-render of TmpView
myObservable.temp += 1
}
Button("test") {
myObservable.items.append(myObservable.items.last!+1)
}
}
}
}
But is there maybe a more elegant way?