SwiftUIで NavigationLinkで遷移した画面から戻ってきたときのイベントをハンドルしたい

NavigationLinkを使って画面Aから画面Bへ遷移して、画面Bから戻ったときにたとえばデータの再読み込みなどなんらかの処理をしたいが、普通にViewを書いていると 戻ってきたときに onAppear が呼ばれない現象が発生する。

f:id:ch3cooh393:20200731172501p:plain

本記事では、NavigationLinkを使って遷移した画面から戻ってきたときに なんらかの処理をする方法を紹介する。

実行環境

  • Xcode 11.6
  • iOS 13.6

問題の挙動

下記のように遷移元と遷移先の2画面用意した。

import SwiftUI

/// 遷移元の画面
struct SampleNavigationView: View {
    
    var body: some View {
        NavigationView {
            List {
                NavigationLink("遷移する", destination: 遷移先View().onDisappear {
                    print("遷移先 onDisappear")
                })
            }
            .navigationBarTitle("遷移元")
        }
        .onAppear {
            print("遷移元 onAppear")
        }
        .onDisappear {
            print("遷移元 onDisappear")
        }
    }
}

/// 遷移先の画面
struct 遷移先View: View {
    
    var body: some View {
        Text("Hello, World!")
            .navigationBarTitle("遷移先")
    }
}

解決編

画面Aから画面Bへ遷移して、画面Bから戻ったときになんらかの処理をする場合、 NavigationLink の引数 destinationに指定しているViewに対して onDisappear modifierを設定すれば、戻ってきたイベントをハンドルすることができる。

具体的には NavigationLink を下記のように書く。

NavigationLink("遷移する", destination: SampleNavigation2View().onDisappear(perform: {
    print("遷移先 onDisappear")
}))

画面のコード全体は以下の通りだ。

/// 遷移元の画面
struct SampleNavigationView: View {
    
    var body: some View {
        NavigationView {
            List {
                NavigationLink("遷移する", destination: SampleNavigation2View().onDisappear(perform: {
                    print("遷移先 onDisappear")
                }))
            }
            .navigationBarTitle("遷移元")
        }
        .onAppear {
            print("遷移元 onAppear")
        }
        .onDisappear {
            print("遷移元 onDisappear")
        }
    }
}

これで遷移先の画面から戻ってくるとコンソールには print("遷移先 onDisappear") が表示される。