Flutter中的命名路线如何消除重复?

vshtjzan  于 2022-12-27  发布在  Flutter
关注(0)|答案(7)|浏览(139)

我不明白为什么有人应该使用命名路由,与Navigator.pushNamed(),而不是 * 正常**方式 * 与Navigator.push()
tutorial page声明:
如果我们需要在应用程序的多个部分导航到同一个屏幕,这可能会导致代码重复。在这种情况下,定义一个“命名路径”并使用该命名路径进行导航会很方便

重复

使用简单路由时如何产生重复,使用命名路由时如何消除重复?
我不明白有什么区别

Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => SecondRoute()),
  );

Navigator.pushNamed(context, '/second');
    • 在重复的情况下**。
qeeaahzv

qeeaahzv1#

考虑在许多小部件中使用Navigator.push()

// inside widget A:
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondRoute()),
);

// inside widget B:
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondRoute()),
);

// inside widget C:
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondRoute()),
);

现在假设你需要修改你的应用程序,小部件SecondRoute需要在它的构造函数上接收一个值,现在你有一个问题,因为你在不同的位置有相同代码的多个副本,你需要确保你会更新所有这些副本,这可能是乏味的和容易出错的:

// inside widget A:
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondRoute(
      title: 'Title A',
  )),
);

// inside widget B:
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondRoute(
      title: 'Title B',
  )),
)),
);

// inside widget C:
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondRoute(
      title: 'Title A',     // ERROR! Forgot to change the variable after a copy/paste
  )),
)),
);

现在,让我们考虑使用命名路由。

首先,我不会建议任何人直接使用名称进行导航,而是使用static变量引用,这样,如果您将来需要更改它,它的方式更简单和安全,因为您不会忘记在任何地方更新它,如下所示:

class Routes {
  static const String second = '/second';
}

另一种方法是在路由本身中有一个引用,SecondRoute中有一个static const String,这样我们就可以将其用作SecondRoute.routeName
然后,您的小工具将使用以下方式导航:

// inside widget A:
Navigator.pushNamed(context, Routes.second); // Routes.second is the same as '/second'

// inside widget B:
Navigator.pushNamed(context, Routes.second);

// inside widget C:
Navigator.pushNamed(context, Routes.second);

现在,如果您需要在创建SecondRoute时传递一个参数,您可以使用MaterialApponGenerateRoute在一个集中的位置执行此操作,如tutorial explains in more detail

// inside widget A:
Navigator.pushNamed(context, Routes.second, arguments: 'Title A');

// inside widget B:
Navigator.pushNamed(context, Routes.second, arguments: 'Title B');

// inside widget C:
// You can still make mistakes here, but the chances are smaller.
Navigator.pushNamed(context, Routes.second, arguments: 'Title C');
MaterialApp(
  onGenerateRoute: (settings) {
    if (settings.name == Routes.second) {
      final String title = settings.arguments;

      return MaterialPageRoute(
        builder: (context) => SecondRoute(title: title),
      );
    }
  },
);

重复代码的数量减少了,但另一方面,随着路线的增加,onGenerateRoute代码变得更加复杂,因为所有的创建都将集中在那里,所以恕我直言,这更多的是个人喜好,而不是一般的指导方针。

oalqel3c

oalqel3c2#

Push和PushNamed的效果相似,Push将切换到您指定的路由,而PushNamed将切换到具有指定路由名称的路由。

“教程”页面中的复制指的是代码复制,而不是路由复制。

例如,您有一个路径,希望在其中检查用户是否已登录并显示相应的页面
仅使用推送:第一页:

//This is page 1....
 RaisedButton(
          child: Text('Go to second'),
          onPressed: () {
            if (user.state = "login") {
              Navigator.of(context).push(
               MaterialPageRoute(
                builder: (context) => SecondPage(),
              ),
             )
            }else{
              Navigator.of(context).push(
               MaterialPageRoute(
                builder: (context) => SecondPageAnonymous(),
               ),
              )
            }
          }
        )
....

在另一个页面Page 2中,您需要重复相同的代码:

//This is page 2....
 RaisedButton(
          child: Text('Go to second'),
          onPressed: () {
            if (user.state = "login") {
              Navigator.of(context).push(
               MaterialPageRoute(
                builder: (context) => SecondPage(),
              ),
             )
            }else{
              Navigator.of(context).push(
               MaterialPageRoute(
                builder: (context) => SecondPageAnonymous(),
               ),
              )
            }
          }
        )
....

使用PushNamed,只需声明一次,基本上就可以反复重用它。
在您的onGenerateRoute:

onGenerateRoute: (settings) {
switch (settings.name) {
  case '/':
    return MaterialPageRoute(builder: (_) => FirstPage());
  case '/second':
    if (user.state = "login") {
      return MaterialPageRoute(
        builder: (_) => SecondPage()
      );
    }else{
      return MaterialPageRoute(
         builder: (_) => SecondPageAnonymous()
     );
    }

  default:
    return _errorRoute();
 }
},

现在,在项目的任何页面中,您都可以执行以下操作:

Navigator.of(context).pushNamed('/second')

无需在每次使用时重复检查登录甚至错误处理。显而易见的好处是,您可以通过防止***重复代码段***而不是一遍又一遍地重复,来保持整个应用的一致性。
现在,这并不能防止路由的重复!在这个上下文中,push和pushNamed没有什么不同!
但是由于您的路由现在已经命名,您可以轻松地执行popUntil('/')返回路由的第一个示例,而不是再次创建它或PushReplacementNamed。

sc4hvdpw

sc4hvdpw3#

使用Navigate with named routes的唯一优点是在您的MaterialApp中声明路线,这样开发人员只能使用指定的路线,即小部件、页面、
如果任何人使用其他方法,它将给予错误**'onUnknownRoute is called。'**

w8biq8rn

w8biq8rn4#

下面是我的初学者Flutter的想法:

它让代码更简洁:无需在更高级别的小部件中声明路线,新的屏幕就会突然出现,以响应应用程序中发生的任何事情。当你一起声明路线时,理解导航框架/结构要容易得多,在更高级别的小部件中更是如此,特别是对其他开发人员来说。当然,这并不能帮助理解这些路线实际上是什么时候导航的,但这是一个小小的改进,并把我们带回到声明范式。声明路线提供的提示将帮助新开发人员理解你的导航流程。

n8ghc7c1

n8ghc7c15#

如果使用push(),则每次需要导航到SecondRoute所在的屏幕时都必须导入该文件,这对于需要在不同屏幕之间导航的大型项目来说是过多的代码重复。
如果您使用pushNamed(),只需在MaterialApp中定义一次路线,即可从任意位置导航至任意屏幕,而无需像使用push()时那样重复操作。
选择PushNamed()的另一个重要原因是可以用它来构建自己的导航系统,甚至在用户导航到屏幕之前,你就可以决定是否为他们提供路线。

y1aodyip

y1aodyip6#

为了理解为什么我们应该使用Navigator.pushNamed而不是Navigator.push,首先让我们熟悉Navigator方法。您是否曾经关心过Navigator.popUntilNavigator.pushAndRemoveUntil?我们使用Navigator.popUntil,直到我们想要在堆栈中弹出到特定的路径。如果您查看文档,您会发现使用pushNamed方法非常容易。此外,检查文档中的所有方法.当我试图理解flutter this中的路由时,文章对我非常有用.并且作为缺点,在这个方法中很难处理参数.你应该创建onGenerateRoute并处理每个路由的参数.

dtcbnfnu

dtcbnfnu7#

对于在2022年访问此问题的人。Flutter实际上现在建议不要使用命名路线
注:大多数应用程序不再建议使用命名路由。有关详细信息,请参阅navigation overview页中的Limitations
https://docs.flutter.dev/cookbook/navigation/named-routes

相关问题