如何在没有上下文的情况下在 Flutter 中使用 GoRouter 进行路由?

问题描述 投票:0回答:5

我要解决的问题: 我的应用程序使用 GoRouter 需要能够从 main() 内路由到命名路由。由于大多数路由都是“context.go”的形式,所以我不能在 main 中这样做。

背景

我的应用程序使用GoRouter。 GetX 让我轻松定义命名路由并从 main() 传递参数,这非常完美。

然而,GetX 和 GoRouter 最终给我带来了问题。 GoRouter 最终将在应用程序的其他部分没有上下文。

如果有一种方法可以让它们简单地共存,我会持开放态度。

我使用了 GetIt 包的服务定位器模式来与 navigatorKey 关联。 当我测试它时它会起作用——但这涉及创建两个 MaterialApp。

但是,这个应用程序使用GoRouter,它似乎没有使用navigatorKey。

我想从 main() 内部转到特定路线。 似乎服务定位器模式可以适用于 GoRouter,就像适用于 MaterialApp 的 Navigator 2.0 一样 - 但我找不到如何执行此操作的示例。

更详细的背景:

这是我目前在 main() 中的内容。

你可以看到我面临的关键挑战是在 main 中传递数据参数的监听器(我从第三方 SDK 得到这个——我不需要它在 main 中,但它需要监听无论应用程序的状态如何)。

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  FFAppState(); // Initialize FFAppState

  GetSocial.addOnInitializedListener(() => {
        // GetSocial SDK is ready to use
      });

  setupLocator();

  runApp(MyApp());

  locator<LandingPageData>().referralID = "defaultReferralID";

  registerListeners();
}

void registerListeners() {
  Invites.setOnReferralDataReceivedListener((received) {
    globalReferralData = received;
    print(globalReferralData);
    print(globalReferralData.linkParams);

    print("listener - socialdata");

    String passedReferralID =
        globalReferralData.linkParams['referralID'].toString();
    String passedCreatorID =
        globalReferralData.linkParams['creatorID'].toString();
    String passedCampaignID =
        globalReferralData.linkParams['\$campaign_id'].toString();

    print(passedReferralID);
    print(passedCreatorID);
    print(passedCampaignID);

    // How can I route to a named Route?

    locator<LandingPageData>().referralID = passedReferralID;
    locator<LandingPageData>().creatorID = passedCreatorID;
    locator<LandingPageData>().campaignID = passedCampaignID;
  });
}

这是 locator.service.dart 的样子:

final locator = GetIt.instance;

class NavigationService {
  final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
  // final GlobalKey<ScaffoldMessengerState> navigatorKey = GlobalKey<ScaffoldMessengerState>();
}

当我可以附加到 navigatorKey 然后从侦听器内导航时,上述方法就起作用了。 但这似乎不起作用,因为应用程序的其余部分使用 GoRouter。

flutter service-locator gorouter
5个回答
17
投票
static BuildContext? get ctx => myGoRouter.routerDelegate.navigatorKey.currentContext;

您可以通过这种方式在您的 NavigationService 中获取上下文并像这样使用它

NavigationService.ctx?.go(...)

您可能面临的问题是 ctx 在应用程序状态下将为空,直到您的第一个页面开始构建。如果您的侦听器有数据而 ctx 仍为空,则路由将不起作用。但你可以像这样处理这种情况:

在主函数或服务中定义全局 tempPageToGo

var _ctx = NavigationService.ctx;
if(_ctx == null) {
  tempPageToGo = anyPageDataYouWant;
  while((await Future.delayed(Duration(seconds: 1))) == null) {
    if(_ctx != null) {
      _ctx!.go(...);
      break;
    }
  }
} else _ctx!.go(...);

17
投票

我们可以使用路由器对象在没有上下文的情况下进行导航。

final router= GoRouter(....);

现在导航使用,

router.push(...);

4
投票

不幸的是,如果我是你,我会放弃使用 GetX 或 GoRouter。

实际上,我会放弃 GetX。

原因是 GetX 在幕后发挥了神奇作用,提高了开发人员的责任和使用

BuildContext
的能力,但这显然是一种反模式,因为 Flutter 的内置导航明显使用了
context
:想想
Navigator.of 
,例如。

GoRouter
围绕
context
构建,并简化了执行“Navigator 2.0”操作所需的大量实现。

如果您尝试实现深层链接,您的

MaterialApp
在根小部件中应该如下所示:

return MaterialApp.router(  // Flutter's Router 2.0 usage
  title: 'MyApp',
  routeInformationProvider: myGoRouter.routeInformationProvider,
  routeInformationParser: myGoRouter.routeInformationParser,
  routerDelegate: myGoRouter.routerDelegate,
);

如果 GetX 允许您将

myGoRouter
放在那里,那么您应该可以开始了。但正如我之前所说,每次您需要显式导航时,您都需要上下文。


3
投票

我正在研究在我的项目中采用 go_router,并且我也被这个用例所困扰(在我的例子中,我试图证明我可以从来自 appsflyer SDK 的回调的延迟链接进行导航)。

对于解决方案,就像 go_router 允许我们从路由器声明下方的上下文或从重定向状态导航。所以我们可以总结影响导航的所有状态。 这就是我从 appRouterState 重定向的方式

redirect: (GoRouterState state) {
  String? redirection(GoRouterState state) {
    final appRouterState = ref.read(appRouterStateNotifierProvider);
    final isAuthed = appRouterState.email != null;

    if (appRouterState.deferredLink != state.location && appRouterState.deferredLink != null) {
        return appRouterState.deferredLink;
    }

    if (state.location != '/login' && !isAuthed) return '/login';
    if (state.location == '/login' && isAuthed) return '/';

    return null;
  }
  final result = redirection(state);
  return result;
},

在您的情况下,您可以在 appRouterStateProvider 或其他内容中实现

setOnReferralDataReceivedListener
。并将其用于
refreshListenable
构造函数中的
GoRouter
参数。

希望这有帮助。


0
投票

我们可以通过这种方式在没有上下文的情况下使用 go_router -

在main.dart中:

MaterialApp.router(
    routerDelegate: router.routerDelegate,
    routeInformationParser: router.routeInformationParser,
    routeInformationProvider: router.routeInformationProvider,
  );

和路由器文件 -

final router = GoRouter(
initialLocation: RoutePaths.home,
routes: [
GoRoute(
  name: RouteNames.home,
  path: RoutePaths.home,
  builder: _buildRoute((context, state) => const HomePage()),
),
 // .... more routes ...
],
);

现在只需使用:

router.pushNamed(
      RouteNames.productdetails,
      pathParameters: {
        'productId': productId.toString(),
      },
    );

通过使用它,我们可以在没有上下文的情况下使用 go router,我已将其用于通知处理。

© www.soinside.com 2019 - 2024. All rights reserved.