You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter+Beamer+Riverpod热重载触发GlobalKey重复使用错误

问题:Beamer+Riverpod实现标签页热重载时GlobalKey冲突

场景说明

用Beamer实现带独立导航栈的底部标签页,标签列表由Riverpod的routeProvider提供,选中状态由tabSelectionProvider监听,逻辑和Beamer官方示例类似,但标签不是硬编码的。

报错信息

热重载时触发以下错误:

Multiple widgets used the same GlobalKey.
The key [GlobalKey#e2e03 beamer-/hq] was used by multiple widgets. The parents of those widgets were:

  • IndexedStack(alignment: AlignmentDirectional.topStart, fit: loose, dependencies: [Directionality], renderObject: RenderIndexedStack#51cdd relayoutBoundary=up1 NEEDS-PAINT)
  • IndexedStack(alignment: AlignmentDirectional.topStart, fit: loose, dependencies: [Directionality], renderObject: RenderIndexedStack#090dd relayoutBoundary=up1)
    A GlobalKey can only be specified on one widget at a time in the widget tree.

问题分析

核心是根节点的IndexedStack包含多个Beamer组件,已经通过全局缓存beamerCache和delegateCache确保每个标签的Beamer和Delegate只创建一次,保留导航状态。但热重载时,build方法返回新的IndexedStack,旧的IndexedStack未被及时销毁,导致新旧栈中的同一个Beamer(复用了GlobalKey)同时存在于 widget 树中,触发冲突。怀疑是竞态条件或引用循环导致旧组件未释放。

实现代码

Map<String, Beamer> beamerCache = {};
Map<String, BeamerDelegate> delegateCache = {};

/// A widget class that shows the BottomNavigationBar and performs navigation
/// between tabs
class ScaffoldWithBottomNavBar extends ConsumerWidget {
  const ScaffoldWithBottomNavBar({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final routes = ref.watch(routeProvider);
    final selectedTab = ref.watch(tabSelectionProvider).selectedTab;
    final tabs = routes.tabs;
    final theme = Theme.of(context);

    final delegates = [for (var tab in tabs) makeDelegate(tab)];

    return Scaffold(
      body: IndexedStack(
        index: selectedTab,
        children: [
          for (var delegate in delegates)
            makeBeamer(delegate.initialPath, delegate)
        ],
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: selectedTab,
        items: [
          for (var tab in tabs)
            BottomNavigationBarItem(label: tab.label, icon: Icon(tab.icon))
        ],
        selectedItemColor: theme.toggleableActiveColor,
        unselectedItemColor: theme.primaryColorDark,
        onTap: (index) {
          if (index != selectedTab) {
            ref.read(tabSelectionProvider.notifier).setTab(index);
            delegates[index].update(rebuild: false);
          }
        },
      ),
    );
  }

  BeamerDelegate makeDelegate(TabInfo tab) {
    var delegate = delegateCache[tab.path];
    if (delegate != null) {
      return delegate;
    }

    delegate = BeamerDelegate(
        initialPath: tab.path,
        locationBuilder: (routeInformation, parameters) {
          if (routeInformation.location!.contains(tab.path)) {
            return TabLocation(routeInformation, tab);
          }
          return NotFound(path: routeInformation.location!);
        });

    delegateCache[tab.path] = delegate;
    return delegate;
  }

  Beamer makeBeamer(String path, BeamerDelegate delegate) {
    var beamer = beamerCache[path];
    if (beamer != null) {
      return beamer;
    }

    beamer = Beamer(
      key: GlobalKey(debugLabel: "beamer-$path"),
      routerDelegate: delegate,
    );
    beamerCache[path] = beamer;
    return beamer;
  }
}

求解决方案或调试建议


内容的提问来源于stack exchange,提问作者Sam Deane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 12:15:32