繁体   English   中英

Flutter:提供程序 class 中出现“构建期间调用的 setState() 或 markNeedsBuild()”错误

[英]Flutter: "setState() or markNeedsBuild() called during build" error in provider class

我有一个错误

setState() or markNeedsBuild() called during build.

我在 Flutter(Web)中使用 state 管理的提供程序开发了一个带有侧边栏的 Web 仪表板。

这是完整的堆栈跟踪:

Restarted application in 243ms.
Gleap already initialized.
[GoRouter] Full paths for routes:
             => /login
[GoRouter] setting initial location /events
[GoRouter] Using MaterialApp configuration
User is signed in!
══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
The following assertion was thrown while dispatching notifications for SidebarViewModel:
setState() or markNeedsBuild() called during build.
This _InheritedProviderScope<SidebarViewModel?> widget cannot be marked as needing to build because
the framework is already in the process of building widgets. A widget can be marked as needing to be
built during the build phase only if one of its ancestors is currently building. This exception is
allowed because the framework builds parent widgets before children, which means a dirty descendant
will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
  _InheritedProviderScope<SidebarViewModel?>
The widget which was currently being built when the offending call was made was:
  LayoutBuilder
When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:49     throw_
packages/flutter/src/widgets/framework.dart 4549:11                              <fn>
packages/flutter/src/widgets/framework.dart 4563:14                              markNeedsBuild
packages/provider/src/inherited_provider.dart 577:5                              markNeedsNotifyDependents
packages/flutter/src/foundation/change_notifier.dart 351:24                      notifyListeners
packages/vamos_events_dashboard/ui/widgets/sidebar/sidebar_view_model.dart 27:5  expandSidebar
packages/vamos_events_dashboard/ui/pages/root_page.dart 18:57                    <fn>
packages/flutter/src/widgets/layout_builder.dart 119:70                          layoutCallback
packages/flutter/src/widgets/framework.dart 2605:19                              buildScope
packages/flutter/src/widgets/layout_builder.dart 153:5                           [_layout]
packages/flutter/src/rendering/object.dart 2246:59                               <fn>
packages/flutter/src/rendering/object.dart 1035:15                               [_enableMutationsToDirtySubtrees]
packages/flutter/src/rendering/object.dart 2246:7                                invokeLayoutCallback
packages/flutter/src/widgets/layout_builder.dart 228:7                           rebuildIfNecessary
packages/flutter/src/widgets/layout_builder.dart 316:5                           performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/custom_layout.dart 171:10                         layoutChild
packages/flutter/src/material/scaffold.dart 1055:7                               performLayout
packages/flutter/src/rendering/custom_layout.dart 240:7                          [_callPerformLayout]
packages/flutter/src/rendering/custom_layout.dart 410:14                         performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/proxy_box.dart 1462:11                            performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/layout_helper.dart 56:10                          layoutChild
packages/flutter/src/rendering/stack.dart 595:43                                 [_computeSize]
packages/flutter/src/rendering/stack.dart 622:12                                 performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/proxy_box.dart 3737:13                            performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/widgets/overlay.dart 804:14                                 performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/custom_paint.dart 552:11                          performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/proxy_box.dart 120:7                              performLayout
packages/flutter/src/rendering/object.dart 2135:7                                layout
packages/flutter/src/rendering/box.dart 2418:11                                  layout
packages/flutter/src/rendering/view.dart 170:7                                   performLayout
packages/flutter/src/rendering/object.dart 1973:7                                [_layoutWithoutResize]
packages/flutter/src/rendering/object.dart 999:17                                flushLayout
packages/flutter/src/rendering/binding.dart 513:19                               drawFrame
packages/flutter/src/widgets/binding.dart 884:13                                 drawFrame
packages/flutter/src/rendering/binding.dart 378:5                                [_handlePersistentFrameCallback]
packages/flutter/src/scheduler/binding.dart 1175:15                              [_invokeFrameCallback]
packages/flutter/src/scheduler/binding.dart 1104:9                               handleDrawFrame
packages/flutter/src/scheduler/binding.dart 881:7                                <fn>
dart-sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart 48:19          internalCallback
The SidebarViewModel sending notification was:
  Instance of 'SidebarViewModel'
════════════════════════════════════════════════════════════════════════════════════════════════════

这是三个相关的类:

根页面:

class RootPage extends StatelessWidget {
  const RootPage({required this.widget});

  final Widget widget;

  @override
  Widget build(BuildContext context) {
    final SidebarViewModel sidebarViewModel = context.read<SidebarViewModel>();

    return Scaffold(
      body: LayoutBuilder(
        builder: (_, BoxConstraints constraints) {
          constraints.maxWidth > 1100 ? sidebarViewModel.expandSidebar() : sidebarViewModel.collapseSidebar();
          return Row(children: [const Sidebar(), Expanded(child: widget)]);
        },
      ),
    );
  }
}

边栏:

class Sidebar extends StatelessWidget {
  const Sidebar({super.key});

  @override
  Widget build(BuildContext context) {
    final SidebarViewModel sidebarViewModel = context.watch<SidebarViewModel>();
    // final SidebarViewModel sidebarViewModel = Provider.of<SidebarViewModel>(context, listen: false);

    return SizedBox(
      width: sidebarViewModel.isExpanded ? 250 : 90,
      child: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          children: [
            SidebarEntry(
              title: 'Profil',
              icon: Icons.account_circle_outlined,
              onTap: () {
                if (sidebarViewModel.selectedItem != SidebarItem.profile) {
                  sidebarViewModel.selectItem(SidebarItem.profile);
                  context.go(ProfilePage.route);
                }
              },
              isSelected: sidebarViewModel.selectedItem == SidebarItem.profile,
            ),
            SidebarEntry(
              title: 'Organisation',
              icon: Icons.business_center_outlined,
              onTap: () {
                if (sidebarViewModel.selectedItem != SidebarItem.organization) {
                  sidebarViewModel.selectItem(SidebarItem.organization);
                  context.go(OrganizationPage.route);
                }
              },
              isSelected: sidebarViewModel.selectedItem == SidebarItem.organization,
            ),
            SidebarEntry(
              title: 'Veranstaltungen',
              icon: Icons.calendar_month_rounded,
              onTap: () {
                if (sidebarViewModel.selectedItem != SidebarItem.events) {
                  sidebarViewModel.selectItem(SidebarItem.events);
                  context.go(EventsPage.route);
                }
              },
              isSelected: sidebarViewModel.selectedItem == SidebarItem.events,
            ),
            const Spacer(),
            SidebarEntry(
              title: 'Abmelden',
              icon: Icons.logout,
              onTap: () => context.read<AuthService>().signOut(),
            ),
          ],
        ),
      ),
    );
  }
}

侧边栏视图模型:

enum SidebarItem { profile, organization, events }

class SidebarViewModel with ChangeNotifier {
  SidebarViewModel();

  SidebarItem _selectedItem = SidebarItem.events;
  bool _isExpanded = false;

  SidebarItem get selectedItem => _selectedItem;
  bool get isExpanded => _isExpanded;

  void selectItem(SidebarItem item) {
    _selectedItem = item;
    notifyListeners();
  }

  void toggleSidebarExpansion() {
    _isExpanded = !_isExpanded;
    notifyListeners();
  }

  void expandSidebar() {
    if (_isExpanded) return;
    _isExpanded = true;
    notifyListeners();
  }

  void collapseSidebar() {
    if (!_isExpanded) return;
    _isExpanded = false;
    notifyListeners();
  }
}

如果有人能帮我解决这个错误,我会很高兴。 只有在 ViewModel 中调用“expandSidebar”或“collapseSidebar”方法时才会出现错误。 换句话说:当我使 web window 变小或变大时,它会触发 RootPage 中的构建方法,然后触发展开或折叠侧边栏方法。

该错误意味着在您的build()方法中的某处调用了setState()markNeedsBuild() 所以 build() function 基本上会在尚未完成时一次又一次地调用自己。

一个简单的解决方法可能是使用后帧回调

// build method of your RootPage widget
@override
  Widget build(BuildContext context) {
    final SidebarViewModel sidebarViewModel = context.read<SidebarViewModel>();

    return Scaffold(
      body: LayoutBuilder(
        builder: (_, BoxConstraints constraints) {
          WidgetsBinding.instance!.addPostFrameCallback((_) {
              // executes after build
              constraints.maxWidth > 1100 
                  ? sidebarViewModel.expandSidebar() 
                  : sidebarViewModel.collapseSidebar();
          });
          return Row(children: [const Sidebar(), Expanded(child: widget)]);
        },
      ),
    );
  }

我还没有机会自己测试这个。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM