GoRouter.dev

Historical source · 2021–2022

日本語アーカイブ · Navigator との併用

原文・コード例・画像を保存した2021–2022年のドキュメント。

Edition published 21 Oct 2026Original APIs
On this page
Recovered from an earlier source commit dated 2021-12-24. This guide was later removed from the main snapshot.
これは2021–2022年の原文アーカイブです。旧APIの例が含まれます。2026年版の英語ガイドも参照してください。

go_router は Navigator ウィジェットとの併用も可能です。 以下はこちらのサンプルからの一部抜粋です。

dart / example
Future<void> _addPerson(BuildContext context) async {
  final person = await Navigator.push<Person>(
    context,
    MaterialPageRoute(
      builder: (context) => NewPersonScreen(family: widget.family),
    ),
  );

  if (person != null) {
    setState(() => widget.family.people.add(person));
    context.goNamed('person', params: {
      'fid': widget.family.id,
      'pid': person.id,
    });
  }
}

このサンプルコードでは、まず Navigator を使って NewPersonScreen のページをスタックにプッシュし、AppBar に戻るボタンを表示させています。 そして Navigator.pop を使ってページの結果を元のページに戻しています。 GoRouter を使用していませんが、問題なく動作します。以下は NewPersonScreen のコードを一部抜粋したものです。

dart / example
ButtonBar(children: [
  TextButton(
    onPressed: () => Navigator.pop(context),
    child: const Text('Cancel'),
  ),
  ElevatedButton(
    onPressed: () {
      if (_formKey.currentState!.validate()) {
        final person = Person(
          id: 'p${widget.family.people.length + 1}',
          name: _nameController.text,
          age: int.parse(_ageController.text),
        );

        Navigator.pop(context, person);
      }
    },
    child: const Text('Create'),
  ),
]),

この例のように GoRouter と Navigator を組み合わせて使っていただいても問題ありません。 ただ、Navigator.push を使った場合はブラウザのアドレスの更新ができません。 アドレスを更新する場合は、GoRouter.go か GoRouter.push を使う必要があります。 ところが、go も push も行った先のページの結果を受け取ることができません。 それは GoRouter が、ナビゲーションにディープリンクと動的リンクを組み込む形で使用されることを想定しているからです。 このことはアプリのロケーションに関することは全てリンクとして表現できるという点にも表れています。 Navigator.push でその場限りのページを生成し、結果を受け取るというようなことはリンクで表現できるものではありません。

とはいえ、GoRouter で同様のことができないわけではありません。実際、これは GoRouter が想定していたよくある事例です。 新規画面を呼び出す側がナビゲーションの結果を受け取ることができないのであれば、新規画面側でユーザーによる入力を処理すればいいのです。

dart / example
ButtonBar(children: [
  TextButton(
    onPressed: () =>
      // ここは Navigator.pop(context) や context.pop() でも可能
      context.goNamed('family', params: {'fid': widget.family.id}),
    child: const Text('Cancel'),
  ),
  ElevatedButton(
    onPressed: () {
      if (_formKey.currentState!.validate()) {
        final person = Person(
          id: 'p${widget.family.people.length + 1}',
          name: _nameController.text,
          age: int.parse(_ageController.text),
        );

        widget.family.people.add(person);

        context.goNamed('person', params: {
          'fid': widget.family.id,
          'pid': person.id,
        });
      }
    },
    child: const Text('Create'),
  ),
]),

この実装により、新規 person 追加用のページを生成するサブルートを設定できるようになりました。

dart / example
GoRoute(
  name: 'home',
  path: '/',
  builder: ...,
  routes: [
    GoRoute(
      name: 'family',
      path: 'family/:fid',
      builder: ...,
      routes: [
        GoRoute(
          name: 'person',
          path: 'person/:pid',
          builder: ...,
        ),
        GoRoute(
          name: 'new-person',
          path: 'new-person',
          builder: (context, state) {
            final family = Families.family(state.params['fid']!);
            return NewPersonScreen(family: family);
          },
        ),
      ],
    ),
  ],
),

結果、_addPerson メソッドは次のようになります。

dart / example
void _addPerson(BuildContext context) {
  context.goNamed('new-person', params: {'fid': widget.family.id});
}

最後に、アプリの様々な場所で使われるデータに変更を加える場合、その状態に依存するウィジェットが確実に再構築されるよう気を配る必要があります。 (例えば、Family の Person オブジェクトのリストに変更を加えるページとは別に、その内容を表示するページがある場合など) これには provider などの状態管理ソリューションを使用することをおすすめします。

GoRouter と Navigator を一緒に使ってはいけない理由はありません。 ただ、アプリの状態をどのように管理していくか、Navigator と GoRouter をそれぞれ利用する意義についてはよく考える必要があります。

Sources & version context

GoRouter.dev documentation edition. The preserved text describes the original package APIs. Follow the current guide before using it in a new project.

Find your next route