I come from React where I use useMemo
to make sure some computation isn't executed too often. How would I do something like that in SwiftUI?
Consider this example:
struct MyView: View {
var records: [Record]
var body: some View {
Text("expensive summary: \(self.expensiveSummary)")
}
var expensiveSummary: String {
// based on records, return string
// containing a summary of records
return ""
}
}
Is there any way to make sure my expensiveSummary
is only called when my array of Records changed?
I think we can create a wrapper view as Equatable
.
(Perhaps, can we use EquatableView
or .equatable()
modifier?)
struct UseMemo<KeyType: Equatable, ViewType: View>: View, Equatable {
let key: KeyType
let content: (KeyType) -> ViewType
var body: some View {
content(key)
}
static func ==(lhs: UseMemo, rhs: UseMemo) -> Bool {
return lhs.key == rhs.key
}
}
struct MyView: View {
@State var records: [Int] = (Array<Int>)(1...10000)
@State var other = false
var body: some View {
VStack {
Button("Update other", action: { self.other.toggle() })
Text("Other: \(String(other))") // This will be called everytime
Button("Update records", action: { self.records.append(1) })
UseMemo(key: records) { keys in
// This is not called even if updated "other"
// This is called when updates "records"
Text("expensive summary: \(expensiveSummary)")
}
// This will be called everytime
Text("expensive summary: \(expensiveSummary)")
}
}
var expensiveSummary: String {
String(records.randomElement()!)
}
}
Followings are helped me.
This is built-in as EquatableView
.
struct MyView: EquatableView { ... }
This will only recompute body
if its properties (records
in this case) actually change, which will prevent expensiveSummary
from being reevaluated.
This won't avoid multiple evaluations of expensiveSummary
inside of body
. If you need to cache that kind of information, you generally should create a local variable (though sometimes function builder syntax won't allow this without extracting parts of the code into a separate function), or compute a property in init
.
As a matter of style, I would recommend against computed properties ever being expensive to evaluate. This is confusing, because property syntax generally suggests the operation is cheap. Instead I would recommend this be a function or computed once in init
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With