Именованные маршруты и go_router

go_router — современный способ описать всю навигацию приложения декларативно, с поддержкой ссылок и редиректов.

Суть: вместо ручных push вы описываете все маршруты как таблицу путей. go_router — рекомендованный пакет 2025 года: он даёт URL-адреса, параметры пути, глубокие ссылки и редиректы по авторизации.

Глубокие ссылки (deep links) — это причина, по которой декларативный роутинг так ценят. Когда пользователь нажимает ссылку на ваш товар в мессенджере или приходит из push-уведомления, операционная система передаёт приложению URL вроде /products/42, и go_router сам разбирает его, открывая нужный экран с нужными данными. С ручным Navigator.push такую логику пришлось бы писать и поддерживать вручную для каждого случая.

Императивная навигация через Navigator.push хороша для пары экранов. Но когда приложению нужны веб-адреса, глубокие ссылки из пушей и редирект неавторизованных на экран входа, ручное управление стеком становится хрупким. Декларативный подход описывает маршруты как карту: путь /users/:id ведёт к экрану профиля. go_router — самый популярный пакет для этого.

final router = GoRouter(
  routes: [
    GoRoute(path: '/', builder: (context, state) => const HomeScreen()),
    GoRoute(
      path: '/users/:id',                    // параметр пути
      builder: (context, state) {
        final id = state.pathParameters['id']!;
        return UserScreen(userId: id);
      },
    ),
  ],
  redirect: (context, state) {
    final loggedIn = checkAuth();
    if (!loggedIn) return '/login';          // редирект по авторизации
    return null;
  },
);

// переход по имени/пути:
context.go('/users/42');
context.push('/users/42');

Параметр :id в пути извлекается через state.pathParameters. context.go заменяет стек на новый маршрут, context.push добавляет поверх. redirect позволяет централизованно перенаправлять — например, гостей на экран входа.

Как работает декларативный роутинг под капотом

go_router построен на Navigator 2.0 — низкоуровневом API, который выставляет весь стек маршрутов наружу и связывает его с URL. Когда приходит ссылка (из браузера, пуша или внутри приложения), роутер сопоставляет путь с таблицей маршрутов, извлекает параметры и строит соответствующий экран. redirect вызывается перед каждым переходом и может перенаправить.

  Ссылка / URL:  /users/42
        |
        v
  +---------------------------+
  |  таблица маршрутов        |
  |  /            -> Home      |
  |  /login       -> Login     |
  |  /users/:id   -> User      |  <- совпадение, id = 42
  +---------------------------+
        |
        v  redirect(): авторизован?
        |  нет -> /login
        |  да  -> продолжить
        v
   UserScreen(userId: '42')
# Модель роутера: сопоставление пути с маршрутом + редирект
import re

routes = {
    r'^/$': 'HomeScreen',
    r'^/login$': 'LoginScreen',
    r'^/users/(?P<id>\d+)$': 'UserScreen',
}

def resolve(path, logged_in=True):
    if not logged_in and path != '/login':
        return 'redirect -> /login'        # редирект гостей
    for pattern, screen in routes.items():
        m = re.match(pattern, path)
        if m:
            params = m.groupdict()
            return f'{screen} {params}' if params else screen
    return 'NotFound (404)'

print(resolve('/'))
print(resolve('/users/42'))
print(resolve('/users/42', logged_in=False))   # -> на /login

Частые ошибки

  • Опечатка в строке пути — типобезопасности у строк нет; для надёжности есть типизированные маршруты (кодогенерация).
  • Забыть обработать 404 — задайте errorBuilder для несуществующих путей.
  • Тяжёлая логика в redirect — он вызывается часто; держите его быстрым.

Best practices

  • Для приложений с вебом, глубокими ссылками и авторизацией используйте go_router.
  • Централизуйте гейтинг доступа в redirect, а не разбрасывайте проверки по экранам.
  • Рассмотрите типизированные маршруты, чтобы исключить опечатки в путях.

go_router поддерживает и вложенную навигацию через ShellRoute — когда нижняя панель вкладок остаётся на месте, а меняется лишь содержимое над ней. Это типичный паттерн приложений с табами внизу. Такие сценарии на голом Navigator реализуются мучительно, а декларативный роутер описывает их как часть всё той же карты маршрутов. Чем крупнее приложение, тем заметнее выигрыш от декларативного подхода.

Итог: go_router превращает навигацию в декларативную карту путей с параметрами, глубокими ссылками и редиректами. Это стандарт 2025 года для серьёзных приложений. Осталось научиться наполнять экраны реальными данными из сети.

Проверьте себя
1. Какое главное преимущество go_router перед ручным Navigator.push?
AОн быстрее рисует виджеты
BДекларативная карта маршрутов с URL, параметрами пути, глубокими ссылками и редиректами
CОн не требует виджетов
DОн заменяет setState
2. Где в go_router удобно централизованно перенаправлять неавторизованных пользователей на экран входа?
AВ каждом экране отдельно
BВ колбэке redirect роутера
CВ методе dispose
DВ pubspec.yaml