Flutter Beamer如何从两个不同位置跳转至同一页面并解决重复key异常
错误原因
这个报错是Flutter导航栈的固有规则限制:同一个Navigator的页面栈中不允许存在两个key完全相同的Page对象。触发问题的核心诱因有两个:
- 你的
LandingLocation代码存在语法疏漏:pathBlueprints数组中的/login、/registration后面没有加逗号,Dart会自动拼接相邻字符串,最终这个数组实际只有一个值/login/registration/contactUs,导致/contactUs路径无法正确匹配到LandingLocation。 - 当你在底部导航页(当前激活的是
NavigationLocation)跳转/contactUs时,Beamer找不到匹配的BeamLocation,就会复用当前的NavigationLocation构建页面栈。而NavigationLocation的buildPages方法会先执行LandingLocation的构建逻辑,检测到路径存在contactUs片段就会插入对应页面,加上你判断页面是否插入用的是pathSegments.contains(只要路径任意段包含对应字符串就会触发插入,没有校验层级),最终导致同一个contactUs的BeamPage被重复插入到栈中,触发key重复报错。
解决步骤
- 修复基础语法错误
给LandingLocation的pathBlueprints数组元素补全逗号:
class LandingLocation extends BeamLocation { @override List<String> get pathBlueprints => [ '/login', '/registration', '/contactUs', ]; // 其余代码保持不变 }
- 优化页面插入判断逻辑
把原来的模糊匹配contains改成精准匹配完整路径,避免深层路径误触发页面插入:
// 仅匹配根路径下的对应页面 if (state.uri.path == '/login') BeamPage( key: ValueKey('login'), child: LoginPage(), ), if (state.uri.path == '/registration') BeamPage( key: ValueKey('registration'), child: RegistrationPage(), ), if (state.uri.path == '/contactUs') BeamPage( key: ValueKey('contactUs'), child: ContactUsPage(), ),
- 调整跳转逻辑,二选一即可
方案A:跳转时重置页面栈为根路径层级
如果希望打开联系我们页面时不显示底部导航栏,直接覆盖整个页面,把底部导航页的跳转代码改成直接指定BeamLocation,确保页面栈被正确替换:
onPressed: () => context.beamTo(LandingLocation(path: '/contactUs')),
方案B:适配底部导航栈结构
如果希望打开联系我们页面时底部导航栏保持显示,就把导航层级的联系我们路径加到NavigationLocation配置中,单独设置不重复的key:
class NavigationLocation extends BeamLocation { @override List<String> get pathBlueprints => [ '/navigation', '/navigation/notifications', '/navigation/profile', '/navigation/contactUs', ]; @override List<BeamPage> buildPages(BuildContext context, BeamState state) => [ ...LandingLocation().buildPages(context, state), if (state.uri.pathSegments.contains('navigation')) BeamPage( key: ValueKey('navigation'), child: NavigationPage(), ), if (state.uri.pathSegments.contains('notifications')) BeamPage( key: ValueKey('notifications'), child: NotificationsPage(), ), if (state.uri.pathSegments.contains('profile')) BeamPage( key: ValueKey('profile'), child: ProfilePage(), ), // 新增导航层级下的联系我们配置 if (state.uri.path == '/navigation/contactUs') BeamPage( key: ValueKey('navigation-contactUs'), child: ContactUsPage(), ), ]; }
对应底部导航页的跳转代码改成:
onPressed: () => context.beamToNamed('/navigation/contactUs'),
修改完成后两个位置的跳转都可以正常运行,不会再触发key重复报错。
内容的提问来源于stack exchange,提问作者sulenT_Thunder
相关产品推荐
相关产品推荐

