В чем разница между Navigator 1.0 и 2.0?

Ответ

Navigator 1.0 (императивный) — это классический стековый навигатор, управляемый прямыми командами push и pop. Он прост для понимания, но сложен для синхронизации с состоянием приложения (например, с глубокими ссылками).

// Императивный подход
Navigator.of(context).push(
  MaterialPageRoute(builder: (context) => const DetailsScreen()),
);

Navigator 2.0 (декларативный) — это более новая парадигма, где стек страниц (pages) является частью состояния вашего приложения. Вы управляете навигацией, изменяя список страниц, а Flutter сам анимирует переходы.

class AppRouter extends StatefulWidget {
  const AppRouter({super.key});

  @override
  State<AppRouter> createState() => _AppRouterState();
}

class _AppRouterState extends State<AppRouter> {
  // Состояние навигации — список страниц
  List<Page<dynamic>> _pages = [const MaterialPage(child: HomeScreen())];

  void _openDetails() {
    setState(() {
      _pages = [..._pages, const MaterialPage(child: DetailsScreen())];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Navigator(
      pages: _pages,
      onPopPage: (route, result) {
        if (!route.didPop(result)) return false;
        // Обновляем состояние при попытке возврата
        setState(() => _pages.removeLast());
        return true;
      },
    );
  }
}

Ключевые преимущества Navigator 2.0:

  • Полный контроль: Стек страниц — часть вашего состояния, что упрощает интеграцию с state-менеджерами (Bloc, Riverpod).
  • Глубокие ссылки: Прямая синхронизация URL (в веб) или роута с состоянием навигации.
  • Сложные сценарии: Упрощает реализацию вложенных навигаторов, модальных потоков.

На практике для большинства приложений я использую пакеты-надстройки, которые реализуют Navigator 2.0, такие как go_router или auto_route. Они скрывают boilerplate-код, предоставляя удобный API для объявления роутов и работы с глубокими ссылками.

Ответ 18+ 🔞

Слушай, давай разберем эту дичь с навигаторами во Flutter, а то у некоторых от этих версий уже глаза на лоб лезут, как у совы на солярисе.

Вот представь: Navigator 1.0 — это как старый добрый пульт от телевизора с кнопками. Хочешь переключить канал? Тыкаешь push — и поехала новая страница. Назад? Жмешь pop — и вернулся. Всё просто, прямолинейно, императивно. Но есть одна, блядь, проблема: синхронизировать этот ручной переключатель каналов с состоянием всего твоего приложения — это тот ещё геморрой. Глубокие ссылки? Ох, ёпта... Тут уже начинается ад.

// Старая школа. Ткнул и поехал.
Navigator.of(context).push(
  MaterialPageRoute(builder: (context) => const DetailsScreen()),
);

А теперь смотри сюда, Navigator 2.0 — это уже не пульт, а умный плейлист. Ты не тыкаешь кнопки, а просто объявляешь: «Слушай, Flutter, вот список страниц, которые должны быть у меня в стеке сейчас». И он сам, хитрая жопа, всё красиво анимирует, добавляет и убирает. Стек страниц становится частью состояния твоего виджета. Сам от себя охуел, когда это понял.

class AppRouter extends StatefulWidget {
  const AppRouter({super.key});

  @override
  State<AppRouter> createState() => _AppRouterState();
}

class _AppRouterState extends State<AppRouter> {
  // Вот он, весь наш стек. Храним как состояние. Красота!
  List<Page<dynamic>> _pages = [const MaterialPage(child: HomeScreen())];

  void _openDetails() {
    setState(() {
      // Говорим: "Добавь ещё одну страницу в конец"
      _pages = [..._pages, const MaterialPage(child: DetailsScreen())];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Navigator(
      pages: _pages, // Скармливаем стеку наш список
      onPopPage: (route, result) {
        if (!route.didPop(result)) return false;
        // А когда юзер жмёт назад, просто удаляем последнюю страницу из состояния
        setState(() => _pages.removeLast());
        return true;
      },
    );
  }
}

И в чём же, блядь, кайф?

  • Полный контроль, ёб твою мать! Твой стек теперь не какая-то тёмная магия, а обычный список в твоём стейте. Захотел — синхронизировал с Bloc или Riverpod, и нет проблем.
  • Глубокие ссылки. Это просто пиздец как удобно. URL в вебе или роут в мобилке теперь напрямую отражают твой стек. Никаких костылей.
  • Сложные сценарии. Вложенные навигаторы, модальные окна, которые должны влиять на историю — с Navigator 2.0 это перестаёт быть квестом на выживание.

Но честно? Писать весь этот boilerplate-код вручную — это, конечно, овердохуища работы. Поэтому все адекватные люди, чувак, берут готовые решения поверх 2.0. go_router или auto_route — вот это реальные пацаны. Они под капотом используют эту декларативную мощь, но дают тебе такой удобный API, что просто волнение ебать. Объявил роуты, настроил глубокие ссылки — и не паришься.