go_routerでSub-routesとして定義したページへの遷移について

# はじめに

go_routerにおいて、Sub-routesとして定義したページに対してgo/pushで遷移した場合の挙動（スタックの積まれ方）について確認したので、それの備忘録となります。

# 動作確認

確認のため、以下3つの画面を用意しました。
Home画面にはPage1Detailへ遷移するための、go/pushメソッドを登録したボタンを配置してあります。(Page1への遷移ボタンは特に無し)

|  Home  |  Page1   | Page1Detail   |
| ---- | ---- | ---- |
|  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658739/a0e87d1b-ed91-f893-9984-e56595ce96f7.png" width="300px">  |  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658739/2e205928-e686-8de3-54f6-56d2951b2b4d.png" width="300px">  |  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658739/87435e5a-56f9-1547-e9ed-3b38009768b4.png" width="300px">  |








## 全てのページをトップレベルで定義した場合 :palm_tree:

Sub-routesを使った場合と比較するため、まずは全てのページをトップレベルで定義した場合の挙動について確認します。


```dart
//全てのページをトップレベルで定義
final GoRouter _router = GoRouter(
  routes: <GoRoute>[
    GoRoute(
      path: '/',
      builder: (context, state) => const Home(),
    ),
    GoRoute(
      path: '/page1',
      builder: (context, state) => const Page1(),
    ),
    GoRoute(
      path: '/page1/detail',
      builder: (context, state) => const Page1Detail(),
    ),
  ],
);
```

### goによる遷移

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658739/955a33ac-0db8-5208-633a-b3858c561d14.gif" width="300px">



Page1Detailのみのスタックに変わるので、戻るキーを押すとアプリが終了します。

スタックの状況

|  遷移前  | 遷移後   |
| ---- | ---- | 
| Home  |       Page1Detail  |


### pushによる遷移

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658739/506f35ae-791e-7ff8-2978-4a02a8289395.gif" width="300px">



遷移前のスタックに遷移後のページが積まれるので、戻るキーで前の画面に戻れます。

|  遷移前  | 遷移後   |
| ---- | ---- | 
| Home  |       Page1Detail  |
|   |      Home  |



## 階層ごとにsub-routesとして定義した場合 :herb: 

次に、階層(`/`)ごとにsub-routesとして定義した場合の挙動を確認していきます。コードとしては以下のようになります。

```dart
//階層ごとにsub-routesとして定義
final GoRouter _router = GoRouter(
  routes: <GoRoute>[
    GoRoute(
      path: '/',
      builder: (context, state) => const Home(),
      routes: <GoRoute>[
        GoRoute(
          path: 'page1',
          builder: (context, state) => const Page1(),
          routes: <GoRoute>[
            GoRoute(
              path: 'detail',
              builder: (context, state) => const Page1Detail(),
            ),
          ],
        )
      ],
    ),
  ],
);
```

### goによる遷移 (sub-routesに対して)


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658739/e4e5beba-6d64-5e73-7afd-ad4db40041bb.gif" width="300px">



**Page1を経由してPage1Detailに遷移したわけではないですが、スタックにはPage1も存在します。** 
これがsub-routesとして定義したページへの遷移の特徴かと思います。

|  遷移前  | 遷移後   |
| ---- | ---- | 
| Home  | Page1Detail  |
|   |     Page1  |
|   |      Home  |

### pushによる遷移 (sub-routesに対して)


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658739/5c101535-5aca-c0f0-8235-82837e540298.gif" width="300px">




遷移前のスタックに遷移後のページが積まれた形となり、挙動としては全てをトップレベルで定義した場合のpushと同じです。


|  遷移前  | 遷移後   |
| ---- | ---- | 
| Home  |       Page1Detail  |
|   |      Home  |

# まとめ

sub-routesとして定義したページにgoメソッドで遷移する場合は、そのページの親もスタックに積まれた状態（さらに親が存在する場合はそれも積まれて...という具合）で遷移することの確認ができました。（goメソッドはスタックを丸々入れ替えるので）

以上です。

# 参考

[sub-routes - gorouter.dev](https://gorouter.dev/sub-routes)