为什么我应该使用命名路由?

Sou*_*SIS 10 flutter

我搜索了很多有关“使用命名路线在屏幕之间导航的好处是什么”的信息。我找不到任何实际的好处,实际上它有很多缺点并且令人讨厌。

1. flutter文档中说命名路由是为了避免代码重复。

例如,如果我想使用 String 一个参数导航到 SecondRoute,它会从此更改

Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondRoute('Some text')),
);
Run Code Online (Sandbox Code Playgroud)

对此

Navigator.pushNamed(context, SecondRoute.routeName, arguments: 'Some text');
Run Code Online (Sandbox Code Playgroud)

我需要在主文件中注册它

MaterialApp(
  onGenerateRoute: (settings) {
    if (settings.name == SecondRoute.routeName) {
      final String text = settings.arguments as String;
      return MaterialPageRoute(
        builder: (context) => SecondRoute(text),
      );
    }
  },
);
Run Code Online (Sandbox Code Playgroud)

如果我有更多路线,我需要为每个路线处理和分配参数。这不是更多的重复和复杂性吗?

setting.arguments没有类型,那不是很糟糕吗?

2. 使用时无法选择使用哪个构造函数pushNamed

例如,我有两个构造函数defaultotherConstructor

class SecondRoute extends StatelessWidget {
  static const String routeName = '/second';
  String? text;

  SecondRoute(this.text);

  SecondRoute.otherConstructor(String text) {
    this.text = 'Other Constructor: ' + text;
  }
}
Run Code Online (Sandbox Code Playgroud)

我如何知道pushNamed我想使用哪一个。

我有一个想法将构造函数名称作为参数传递并像这样检查它

Navigator.pushNamed(context, SecondRoute.routeName, arguments: ['default' or 'otherConstructor','Some text']);
Run Code Online (Sandbox Code Playgroud)

在主文件中

MaterialApp(
  onGenerateRoute: (settings) {
    if (settings.name == SecondRoute.routeName) {
      final args = settings.arguments as List<String>;
      if (args[0] == 'otherConstructor') {
        return MaterialPageRoute(
          builder: (context) => SecondRoute.otherConstructor(text),
        );
      } else if (args[0] == 'default') {
        return MaterialPageRoute(
          builder: (context) => SecondRoute(text),
        );
      }
    }
  },
);
Run Code Online (Sandbox Code Playgroud)

但这非常非常复杂,显然不是一个好方法。

3. reddit 和 stackoverflow 中的一些 anwsers 说命名路由通过将每个路由保留在主文件中使代码更加集中。

集中化当然是好的,但为什么不采取其他方式呢?

例如,将所有包含路由的 dart 文件保留在新文件夹中

在此输入图像描述

有人可以告诉我为什么大多数人使用命名路线吗?谢谢你的帮助。

nie*_*eka 9

从我的角度来看,我个人认为您担心的根本原因是您继续使用构造函数或注入在屏幕上传递数据。

参考flutter官方文档:https://docs.flutter.dev/development/data-and-backend/state-mgmt/declarative

我是一名拥有 UI 工具包的 iOS 开发人员,所以我认为你和我有同样的问题,我通过改变我的思维流程解决了这个问题。

重要的事情:从声明式 UI 图片来看:UI = f(state)。

对于您的问题(1):

  • 我认为我们不应该在屏幕上传递数据,您可以使用 rxdart、provider、mobx、redux...或任何状态管理。它将保留 UI 渲染的数据,您无需在主文件中的很长的 switch/if 中再次检查它。如果你不断传递参数,那么你就无法从状态构建 UI

对于您的问题(2):

  • 我认为这与(1)有同样的问题。您可以创建状态来反映它,而不是使用许多构造函数。因此,您的屏幕(我的意思是反映您屏幕的小部件,而不是它们的子小部件)可以从状态获取数据,而无需从参数中获取数据。再次强调 UI = f(state)。

对于您的问题(3):

  • 我绝对同意你的观点,将其保存在另一个文件夹中是最好的选择。

注意:就个人而言,我现在将小部件分为两种类型:屏幕小部件和演示小部件。

  • Screen:永远不要向它传递参数,它使用来自 state(UI = f(state)) 的数据
  • 展示小部件:可以在构造函数中接收参数。

最初的想法来自redux的创始人(https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

=>有了这个想法,它清楚地解决了你的问题(1)和(2)。对于(3),通过拆分到另一个文件夹并导入,它应该以主文件中的一些行结束,如下所示(屏幕上没有任何进程参数更改):

在此输入图像描述

为了利益

我个人认为最大的优点是:

1 - 您可以稍后更改屏幕而无需修改工作代码(开闭原则):假设您的客户想要将屏幕 A 更改为屏幕 A',其中在您的代码中有很多导航。

示例:您的应用程序可以从 3 种不同的逻辑进入登录屏幕:从启动画面、从按注销、从管理员禁止消息。

如果您使用:MaterialPageRoute(builder: (context) => SecondRoute('Some text')),那么您需要在完美运行的代码中多次替换它(示例中为3次)。最危险的是:也许“来自管理员禁止消息”的逻辑是来自其他开发者的@@

如果您使用:Navigator.pushNamed(context,SecondRoute.routeName,arguments:'Some text'),您可以通过将其重定向到另一个屏幕(新的登录屏幕)来更改拆分文件夹中的代码(您在(3)中提到的)

下面的事情我认为不太重要:

2-(仅注意)如果您使用网页版本构建项目,您将在url地址中包含路由名称,因此它会打开您的页面以获取url。

3-防止大量不必要的导入(例如您可以在登录中看到,如果您使用路由,只需导入1个文件。但是您直接使用导航器,您需要导入许多相关屏幕:注册,忘记密码......)。无论如何,它可以通过创建类似 screen_index.dart 的内容来解决。