Greetings,
Context
Let's imagine 2 possible root Views: House and Castle. They can both present a Room view and this room view can show a Bed view.
Let's also assume, for the sake of the example, that I want to pass the "$sheet" (Identifiable enum) from either House or Castle - which are 2 different enums - all the way to Bed, so that Bed can dismiss back to rootView. So I use a Binding.
Visually, the UI flow is
House --> \
Room --> Bed
Castle --> /
In RoomView and BedView, I expected to receive either a HouseSheet or a CastleSheet. So by receiving one at init, I set to a constant nil the other. For example, if I open a RoomView (or BedView) from a HouseView, the code would be
init(parentHouseSheet: Binding<HouseSheet?>) {
self._parentHouseSheet = parentHouseSheet
self._parentCastleSheet = .constant(nil)
self.from = .house
}
init(parentCastleSheet: Binding<CastleSheet?>) {
self._parentHouseSheet = .constant(nil)
self._parentCastleSheet = parentCastleSheet
self.from = .castle
}
Problem
My problem now is that the .constant(nil) appears to change and triggers a refresh!
By using a simple Self._printChanges()
I get the following when I navigate to a BedView (from a House origin!).
RoomView: _parentCastleSheet changed. // Why? It's a binded constant and I'm not even touching RoomView at all.
BedView: @self, @identity, _parentCastleSheet changed.
BedView: @self, _parentCastleSheet changed. // Same why?
Full code
// House & Castle
enum BuildingOrigin: String {
case house
case castle
}
enum HouseSheet: String, Hashable, Identifiable {
case room
var id: String { return self.rawValue }
}
enum CastleSheet: String, Hashable, Identifiable {
case room
var id: String { return self.rawValue }
}
// I only show HouseView for this example.
struct HouseView: View {
@State private var sheet: HouseSheet?
var body: some View {
let _ = Self._printChanges()
VStack {
Button("Open Room (Sheet)") {
self.sheet = .room
}
}
.padding()
.sheet(item: $sheet) { sheet in
switch sheet {
case .room: RoomView(houseSheet: $sheet)
}
}
}
}
// Room
enum RoomViewDestination: String, Hashable {
case bed
}
struct RoomView: View {
@State private var path = NavigationPath()
@Binding var parentHouseSheet: HouseSheet?
@Binding var parentCastleSheet: CastleSheet?
let from: BuildingOrigin
init(houseSheet: Binding<HouseSheet?>) {
self._parentHouseSheet = houseSheet
self._parentCastleSheet = .constant(nil)
self.from = .house
}
init(castleSheet: Binding<CastleSheet?>) {
self._parentHouseSheet = .constant(nil)
self._parentCastleSheet = castleSheet
self.from = .castle
}
var body: some View {
let _ = Self._printChanges()
NavigationStack(path: $path) {
List {
NavigationLink(value: RoomViewDestination.bed) {
Text("Open Bed (Navigation)")
}
}
.navigationDestination(for: RoomViewDestination.self) { destination in
switch destination {
case .bed:
switch self.from {
case .house: BedView(parentHouseSheet: $parentHouseSheet)
case .castle: BedView(parentCastleSheet: $parentCastleSheet)
}
}
}
}
}
}
// Bed
struct BedView: View {
@Binding var parentHouseSheet: HouseSheet?
@Binding var parentCastleSheet: CastleSheet?
let from: BuildingOrigin
init(parentHouseSheet: Binding<HouseSheet?>) {
self._parentHouseSheet = parentHouseSheet
self._parentCastleSheet = .constant(nil)
self.from = .house
}
init(parentCastleSheet: Binding<CastleSheet?>) {
self._parentHouseSheet = .constant(nil)
self._parentCastleSheet = parentCastleSheet
self.from = .castle
}
var body: some View {
let _ = Self._printChanges()
Text("The \(from.rawValue) has a nice bed.")
}
}