How to optionally pass in a Binding in SwiftUI?
The main problem with what you want to achieve is that when the index is handled by the parent your View needs a @Binding to it, but when it handles the index itself it needs @State. There are two possible solutions.
If the view can ignore the index property when it doesn't have one:
struct ReusableView: View {
@Binding var index: Int?
init(_ index: Binding<Int?>) {
self._index = index
}
init() {
self._index = .constant(nil)
}
var body: some View {
VStack {
index.map { Text("The index is \($0)") }
}
}
}
The advantage is that it is very straightforward - just two initializers, but you cannot change the value of the index when it is handled by ResusableView itself (its a constant).
If the view cannot ignore the index property when it doesn't have one:
struct ReusableView: View {
private var content: AnyView
init(_ index: Binding<Int>? = nil) {
if let index = index {
self.content = AnyView(DependentView(index: index))
} else {
self.content = AnyView(IndependentView())
}
}
var body: some View {
content
}
private struct DependentView: View {
@Binding var index: Int
var body: some View {
Text("The index is \(index)")
}
}
private struct IndependentView: View {
@State private var index: Int = 0
var body: some View {
Text("The index is \(index)")
}
}
}
The clear advantage is that you have a view that can either be bound to a value or manage it as its own State. As you can see ReusableView is just a wrapper around two different views one managing its own @State and one being bound to @State of its parent view.