-
-
Save jegnux/c3aee7957f6c372bf31a46c893a6e2a2 to your computer and use it in GitHub Desktop.
import SwiftUI | |
import Combine | |
public struct ChangeObserver<V: Equatable>: ViewModifier { | |
public init(newValue: V, action: @escaping (V) -> Void) { | |
self.newValue = newValue | |
self.newAction = action | |
} | |
private typealias Action = (V) -> Void | |
private let newValue: V | |
private let newAction: Action | |
@State private var state: (V, Action)? | |
public func body(content: Content) -> some View { | |
if #available(iOS 14, *) { | |
assertionFailure("Please don't use this ViewModifer directly and use the `onChange(of:perform:)` modifier instead.") | |
} | |
return content | |
.onAppear() | |
.onReceive(Just(newValue)) { newValue in | |
if let (currentValue, action) = state, newValue != currentValue { | |
action(newValue) | |
} | |
state = (newValue, newAction) | |
} | |
} | |
} | |
extension View { | |
@_disfavoredOverload | |
@ViewBuilder public func onChange<V>(of value: V, perform action: @escaping (V) -> Void) -> some View where V: Equatable { | |
if #available(iOS 14, *) { | |
onChange(of: value, perform: action) | |
} else { | |
modifier(ChangeObserver(newValue: value, action: action)) | |
} | |
} | |
} |
Also i'm getting [SwiftUI] Modifying state during view update, this will cause undefined behavior.
on line 27, which is fixable by adding .receive(on: DispatchQueue.main)
operator to the Just
on line 13
-> .onReceive(Just(newValue).receive(on: DispatchQueue.main)) { newValue in
+1 To what is the purpose of onAppear
@KoCMoHaBTa @kuanfajardo I don't remember well but it was probably a workaround to some bug.
This is such a beautiful solution...... wow......
Great solution! Saved me. Just one question: What's the idea of putting action
into state
? Seems, the action never changes within the struct lifecycle
@subtranix my backports library actually has some improvements and is far more battle tested against a lot more projects id suggest checking that out.
What is the purpose of the
onAppear()
on line 22?