在pub.dev上运行了近一年,经过许多个人和公司的测试和使用,long......
Beamer v1.0.0发布了! 什么是新的和如何迁移
在pub.dev上运行了近一年,经过许多个人和公司的测试和使用,期待已久的_v1.0.0_终于发布了_。
目录
- 简介
- v0.14.1之后的新内容
- 如何迁移
- 最后的想法
简介
Beamer是一个适用于所有平台的路由包,它可以让你使用Router
和Navigator
的Pages API(又称 "Navigator 2.0")在受保护的页面堆栈和URL中导航。
如果你不熟悉这些导航概念,Learning Flutter's new navigation and routing system是一篇可以开始阅读的好文章。本文的其余部分假定熟悉上述概念,并对Beamer有一定的了解,其README可以在下面的链接中阅读。
beamer | Flutter包 处理您的应用程序在所有平台上的路由,使其与浏览器的URL栏同步等等。Beamer使用的动力是... pub.dev/packages/be…
有2个主要想法指导Beamer的诞生。
- 使Router API的使用更容易,特别是对初学者而言
- 将创建页面堆栈的责任分离出来,供中级和高级使用。
第一点是通过对 "RouterDelegate "和 "RouteInformationParser "的默认实现来解决的,即 "BeamerDelegate "和 "BeamerParser"。两者都可以采取各种参数进行定制。拥有命名的路线在一开始就显示出是一个需要的功能,所以有一个RoutesLocationBuilder
,可以用熟悉的routes
地图进行配置。设置完成后,导航可以通过Beamer.of(context).beamToNamed('/my/page/2')
这样的方式完成,这使得从Navigator.of(context).pushNamed('/my-page')
的过渡对新人来说非常自然。
第二点是由一个BeamLocation
的概念完成的,它负责根据它的状态
来决定BeamerDelegate
在(重新)构建时应该把哪些页面放入Navigator.pages
。这里的想法是为应用程序中不同的 "区域/地点/世界 "定义不同的BeamLocation
。例如,我们可以有BooksBeamLocation
来处理一个堆栈中所有与书籍相关的页面组合,还有ArticlesBeamLocation
来处理一个堆栈中所有与文章相关的页面。当需要建立一个包含10多个屏幕的应用程序时,这种方法的好处很快就可以看到,这些屏幕被组织在几个 "上下文不同 "的页面堆栈中。
当定义你的 "BeamLocation "时,用于它的 "state "可以是默认的 "BeamState"(持有对决定如何建立一个页面堆栈很重要的各种路由参数)或一个完全自定义的状态对象,甚至(但不是必须的)一个 "ChangeNotifier"。当使用一个自定义的ChangeNotifier
作为BeamLocation
的状态时,可以完成纯粹的声明式导航。然而,即使使用ChangeNotifier
状态,人们也能同样地进行强制性的导航。Beamer并不偏爱其中的一种,它对两者的处理都是类似的。下一个目标可能是使默认的BeamState
成为ChangeNotifier
,但这是下一篇文章的主题 :)
每个导航动作后发生的流程可以在下图中看到。
v0.14.1之后的新内容
一个完整的变化日志可以看到在pub.dev,所以我们会去看每个突破性变化背后的原因和一些值得一提的地方。
BeamState的变化
- 它现在与
RouteInformationSerializable
混合,这是一个在Beamer中定义的混合元素,每个BeamLocation
的状态都必须与之混合。 pathBlueprintSegments
更名为pathPatternSegments
。
BeamerDelegate的变化
- 你们中的一些人可能会注意到,特别是如果直接使用
Beamer.of(context).update
,BeamerDelegate
也存储其 "状态"。在这之前,这是一个叫做state'的
BeamState',但这感觉不太对。现在这是一个叫做 "configuration "的RouteInformation
,与RouterDelegate
中的名称相同。 - 所有的波束参数,如
transitionDelegate',
beamBackOnPop'和其他的都被提取到一个`BeamParameters'对象中。这不是一个突破性的变化,因为这些参数在波束函数中保持不变,但这是一个变化,与上述变化一起影响了以下变化 locationBuilder
现在接受RouteInformation
和BeamParameters
而不是BeamState
。这是上述变化的自然结果,但也是一个改进,因为它提供了将光束参数
保存到历史中的能力,这在以前是不可能的。beamStateHistory
和beamLocationHistory
被替换为beamingHistory
,它是一个List<BeamLocation>
,每个BeamLocation
都有history
,是List<HistoryElement>
,其中HistoryElement
持有RouteInformation
和BeamParameters
。这句话很快就升级了,但现在我们有一个非常稳定和结构良好的光束历史。listener
被重新命名为routeListener
,并增加了一个新的buildListener
。这样,我们就可以同时监听传入的路由(在构建之前)和构建时(在那里我们也可以访问页面)。
BeamLocation的变化
- 由于 "BeamerDelegate "的变化,构造函数现在需要可选的 "路由信息 "和 "BeamParameters"。
- "状态 "的 "T "型现在必须与 "RouteInformationSerializable "混合,在扩展 "BeamLocation "时,必须为状态指定一个通用类型,即使使用默认的 "BeamState "也是如此。
pathBlueprints'更名为
pathPatterns',是一个List<Pattern>
。
关于SimpleLocationBuilder的变化
- 重命名为
RoutesLocationBuilder
。这是由于Navigator 2.0 API Usability Research的讨论 routes
的值现在也接受Object? data
参数。
BeamPage上的变化
pageRouteBuilder
被更通用的routeBuilder
所取代。- 我们现在有了一个
const
构造函数 - 增加了一个静态的
routePop',可以代替默认的
pathSegmentPop'用于`onPopPage'。
BeamGuard的变化
pathBlueprints
改名为pathPatterns
。beamTo
和beamToNamed
现在也接收origin
和target
,它们是被传送的地方和被传送到的地方的BeamLocation
(这是被保护的)。
对例子的补充
- Guard riverpod example
- Firebase核心实例
- Firebase auth example
- ChangeNotifier自定义状态示例
如何迁移
虽然有很多变化,但迁移是非常直接的。我们将通过2种迁移方案;当使用SimpleLocationBuilder
和使用自定义BeamLocation
时。
简单定位器生成器
正如我们上面提到的,SimpleLocationBuilder
被重新命名为RoutesLocationBuilder
。这就完成了50%的迁移,我们只需要在routes
中添加data
参数,但是让我们写一些代码。
以前我们有这样的东西
代码语言:javascript复制final routerDelegate = BeamerDelegate(
locationBuilder: SimpleLocationBuilder(
routes: {
'/': (context, state) => MyWidget(),
'/another': (context, state) => MyAnotherWidget(),
},
),
// other properties...
);
复制代码
迁移后,我们应该有这样的东西
代码语言:javascript复制final routerDelegate = BeamerDelegate(
locationBuilder: RoutesLocationBuilder(
routes: {
'/': (context, state, data) => MyWidget(),
'/another': (context, state, data) => MyAnotherWidget(),
},
),
// other properties...
);
复制代码
自定义BeamLocation
如前所述,我们必须将pathBlueprints'重命名为
pathPatterns',并在扩展BeamLocation'时放入一个具体的
state'类型。
在0.14.1版本中,我们可以有
代码语言:javascript复制class BooksLocation extends BeamLocation {
@override
List<Pattern> get pathBlueprints => ['/', '/books'];
@override
List<BeamPage> buildPages(BuildContext context, BeamState state) {
return [
BeamPage(
key: const ValueKey('home'),
child: const HomeScreen(),
),
if (state.uri.pathSegments.contains('books'))
BeamPage(
key: const ValueKey('books'),
child: const BooksScreen(),
),
];
}
}
复制代码
现在我们有
代码语言:javascript复制class BooksLocation extends BeamLocation<BeamState> {
@override
List<Pattern> get pathPatterns => ['/', '/books'];
@override
List<BeamPage> buildPages(BuildContext context, BeamState state) {
return [
const BeamPage(
key: ValueKey('home'),
child: HomeScreen(),
),
if (state.uri.pathSegments.contains('books'))
const BeamPage(
key: ValueKey('books'),
child: BooksScreen(),
),
];
}
}
复制代码
注意我们现在可以使用const
构造函数的BeamPage
,而不需要在所有属性上使用它(如果我们用prefer_const_constructors
林特规则开发)。
杂项
访问currentBeamLocation.state
现在,state
类型不能被自动推断(即使它是一个默认的BeamState
),所以我们需要手动铸造它,以便能够访问其类型的所需属性。
之前我们可以做
代码语言:javascript复制final beamState = Beamer.of(context).currentBeamLocation.state;
final bookId = beamState.pathParameters['bookId'];
复制代码
现在我们必须
代码语言:javascript复制final beamState = Beamer.of(context).currentBeamLocation.state as BeamState;
final bookId = beamState.pathParameters['bookId'];
复制代码
BeamGuard
如在BeamLocation
中,pathBlueprints
被重命名为pathPatterns
,beamTo
/beamToNamed
得到了两个参数。
以前我们有
代码语言:javascript复制BeamGuard(
pathBlueprints: ['/login'],
guardNonMatching: true,
check: (context, location) => context.isUserAuthenticated(),
beamToNamed: '/login',
)
复制代码
现在我们有这样的参数
代码语言:javascript复制BeamGuard(
pathPatterns: ['/login'],
guardNonMatching: true,
check: (context, location) => context.isUserAuthenticated(),
beamToNamed: (origin, target) => '/login',
)
复制代码
最后的想法
我希望这篇文章对已经在使用Beamer的人有帮助,甚至对正在考虑开始新的导航概念的人有帮助。这对我来说肯定是(而且是)很有趣的,我计划在将来写更多关于它的文章。
欢迎访问Beamer的GitHub仓库或Discord服务器,以进一步讨论和了解你可能遇到的问题。