Skip to content

Instantly share code, notes, and snippets.

@davbeck
Created July 31, 2020 15:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davbeck/cb1f1515e184759404292a59f9661beb to your computer and use it in GitHub Desktop.
Save davbeck/cb1f1515e184759404292a59f9661beb to your computer and use it in GitHub Desktop.
Callback api for SwiftUI based on React's useEffect hook
struct Child: View {
var count: Int
var body: some View {
Text("Child: \(count)")
.useEffect(Int(floor(Double(count) / 2))) { source in
// this only gets called when the source changes
print("onAppear \(source)")
}
}
}
struct ContentView: View {
@State var count: Int = 0
@ViewBuilder var body: some View {
Child(count: count)
Stepper("Count: \(count)", value: $count)
}
}
struct AsyncEffectView<Source: Hashable>: View {
@State var observer: AnyCancellable? = nil
var source: Source
var action: (Source) -> AnyCancellable
var body: some View {
EmptyView()
.onAppear {
self.observer = self.action(self.source)
}
.onDisappear {
self.observer?.cancel()
}
.id(source)
}
}
extension View {
func useEffect<Source: Hashable>(_ source: Source, perform action: @escaping (Source) -> Void) -> some View {
return self
.overlay(
EmptyView().onAppear {
action(source)
}
.id(source)
)
}
func useEffect<Source: Hashable>(_ source: Source, perform action: @escaping (Source) -> AnyCancellable) -> some View {
return self
.overlay(
AsyncEffectView(source: source, action: action)
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment