title: Is onAppear and onDisappear in a NavigationView of a SwiftUI app behaving as expected?
body: <p>I would like to know if the behavior of onAppear and onDisappear in SwiftUI (Xcode 11 beta 6 when I wrote this) is what a developer would find more useful or it is just being more a problem than a feature.</p>
  
  <p>Right now, if we use a cascaded navigation as you will find in the sample code I attach (that compiles and runs fine in Xcode 11b6), a console output of a user navigating back and forth would just trigger onAppear only in the case of a new view load in the forward direction (meaning going deeper).</p>
  
  <p>In the navigation:
  Root -> NestedView1 -> NestedView2 -> NestedView3 , 
  when adding a debug helper to each view stage,</p>
  
  <pre><code>  .onAppear(perform: {print("onAppear level N")})
    .onDisappear(perform: {print("onDisappear level N")})
  </code></pre>
  
  <p>debug console would show</p>
  
  <p><code>onAppear root level 0</code><br/>
  <code>onAppear level 1</code><br/>
  <code>onAppear level 2</code><br/>
  <code>onAppear level 3</code><br/></p>
  
  <p>(No onDisappear triggering)</p>
  
  <p>but travelling back
  Root &lt;- NestedView1 &lt;- NestedView2 &lt;- NestedView3</p>
  
  <p>debug console would show ... nothing</p>
  
  <p>(No onAppear or onDisappear triggering)</p>
  
  <pre><code>struct NestedViewLevel3: View {
  
      @Environment(\.presentationMode) var presentationMode: Binding&lt;PresentationMode&gt;
  
      var body: some View {
          VStack {
              Spacer()
              Text("Level 3")
              Spacer()
              Button(action: {
                  self.presentationMode.wrappedValue.dismiss()
              }) {
                  Text("Back")
                      .padding(.horizontal, 15)
                      .padding(.vertical, 2)
                      .foregroundColor(Color.white)
                      .clipped(antialiased: true)
                      .background(
                          RoundedRectangle(cornerRadius: 20)
                              .foregroundColor(Color.blue)
                              .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                  )
              }
              Spacer()
          }
          .navigationBarBackButtonHidden(false)
          .navigationBarTitle("Level 3", displayMode: .inline)
          .onAppear(perform: {print("onAppear level 3")})
          .onDisappear(perform: {print("onDisappear level 3")})
  
      }
  }
  
  struct NestedViewLevel2: View {
  
      @Environment(\.presentationMode) var presentationMode: Binding&lt;PresentationMode&gt;
  
      var body: some View {
          VStack {
              Spacer()
              NavigationLink(destination: NestedViewLevel3()) {
                  Text("To level 3")
                      .padding(.horizontal, 15)
                      .padding(.vertical, 2)
                      .foregroundColor(Color.white)
                      .clipped(antialiased: true)
                      .background(
                          RoundedRectangle(cornerRadius: 20)
                              .foregroundColor(Color.gray)
                              .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                  )
                      .shadow(radius: 10)
              }
              Spacer()
              Text("Level 2")
              Spacer()
              Button(action: {
                  self.presentationMode.wrappedValue.dismiss()
              }) {
                  Text("Back")
                      .padding(.horizontal, 15)
                      .padding(.vertical, 2)
                      .foregroundColor(Color.white)
                      .clipped(antialiased: true)
                      .background(
                          RoundedRectangle(cornerRadius: 20)
                              .foregroundColor(Color.blue)
                              .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                  )
              }
              Spacer()
          }
          .navigationBarBackButtonHidden(false)
          .navigationBarTitle("Level 2", displayMode: .inline)
          .onAppear(perform: {print("onAppear level 2")})
          .onDisappear(perform: {print("onDisappear level 2")})
      }
  }
  
  struct NestedViewLevel1: View {
  
      @Environment(\.presentationMode) var presentationMode: Binding&lt;PresentationMode&gt;
  
      var body: some View {
          VStack {
              Spacer()
              NavigationLink(destination: NestedViewLevel2()) {
                  Text("To level 2")
                      .padding(.horizontal, 15)
                      .padding(.vertical, 2)
                      .foregroundColor(Color.white)
                      .clipped(antialiased: true)
                      .background(
                          RoundedRectangle(cornerRadius: 20)
                              .foregroundColor(Color.gray)
                              .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                  )
                      .shadow(radius: 10)
              }
              Spacer()
              Text("Level 1")
              Spacer()
              Button(action: {
                  self.presentationMode.wrappedValue.dismiss()
              }) {
                  Text("Back")
                      .padding(.horizontal, 15)
                      .padding(.vertical, 2)
                      .foregroundColor(Color.white)
                      .clipped(antialiased: true)
                      .background(
                          RoundedRectangle(cornerRadius: 20)
                              .foregroundColor(Color.blue)
                              .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                  )
              }
              Spacer()
          }
          .navigationBarBackButtonHidden(false)
          .navigationBarTitle("Level 1", displayMode: .inline)
          .onAppear(perform: {print("onAppear level 1")})
          .onDisappear(perform: {print("onDisappear level 1")})
      }
  }
  
  struct RootViewLevel0: View {
  
      var body: some View {
          NavigationView {
          VStack {
              Spacer()
              NavigationLink(destination: NestedViewLevel1()) {
              Text("To level 1")
                  .padding(.horizontal, 15)
                  .padding(.vertical, 2)
                  .foregroundColor(Color.white)
                  .clipped(antialiased: true)
                  .background(
                      RoundedRectangle(cornerRadius: 20)
                      .foregroundColor(Color.gray)
                      .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                  )
                  .shadow(radius: 10)
          }
  
              Spacer()
  
              }
      }
  
          .navigationBarTitle("Root level 0", displayMode: .inline)
          .navigationBarBackButtonHidden(false)
          .navigationViewStyle(StackNavigationViewStyle())
          .onAppear(perform: {print("onAppear root level 0")})
          .onDisappear(perform: {print("onDisappear root level 0")})
  
      }
  
  }
  
  
  struct ContentView: View {
      var body: some View {
          RootViewLevel0()
      }
  }
  
  
  }
  </code></pre>
  
  <p>Now, would a developer rather have onAppear and onDisappear:</p>
  
  <p>1) Triggered for the purpose of launching actions that need to be performed only once and only when the user travels forward, like in the current observed behavior.</p>
  
  <p>2) Triggered each time the view appears, more like the action name seems to mean, be it backwards, forwards and any number of times.</p>
  
  <p>I'd take the option 2, simple and brutal (and what I currently need), but I am quite a naive newbie at NavigationView, and option 2 may break a lot of established paradigms I'm not taking into account.</p>
  
  <p>Your feedback will help me find out if the corresponding Feedback Assistant case for SwiftUI is on legitimate grounds.</p>