提供者:在构建期间调用的 setState() 或 markNeedsBuild()

Posted

技术标签:

【中文标题】提供者:在构建期间调用的 setState() 或 markNeedsBuild()【英文标题】:Provider: setState() or markNeedsBuild() called during build 【发布时间】:2021-08-10 13:36:52 【问题描述】:

我正在使用 Hive 存储与 Extension 相关的 Card 项目的整个列表。在所选扩展程序的屏幕中,我正在显示此扩展程序的卡片,并带有一堆过滤器/排序。

为此,我使用ValueListenableBuilder 来获取当前的分机和他们的卡片。

当我过滤/排序此列表时,我想将它们存储到我的Provider 类中,因为我想将此列表重用到另一个屏幕中。

但我们是context.read<ShowingCardsProvider>().setAll(sortedList),我收到了这个错误:

setState() or markNeedsBuild() called during build.

我现在不在任何地方听ShowingCardsProvider

你能解释一下这里出了什么问题吗?

谢谢!

ma​​in.dart

  runApp(MultiProvider(
    providers: [
      ChangeNotifierProvider.value(value: AuthProvider()),
      ChangeNotifierProvider.value(value: UserProvider()),
      ChangeNotifierProvider.value(value: ShowingCardsProvider()),
    ],
    child: MyApp(),
  ));

showing_cards_provider.dart

import 'dart:collection';

import 'package:flutter/material.dart';
import 'package:pokecollect/card/models/card.dart';

class CardsProvider extends ChangeNotifier 
  final List<CardModel> _items = [];

  UnmodifiableListView<CardModel> get items => UnmodifiableListView(_items);

  void setAll(List<CardModel>? items) 
    _items.clear();
    if (items != null || items!.isNotEmpty) 
      _items.addAll(items);
    
    notifyListeners();
  

  void addAll(List<CardModel> items) 
    _items.addAll(items);
    notifyListeners();
  

  void removeAll() 
    _items.clear();
    notifyListeners();
  

extension_page.dart

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      extendBodyBehindAppBar: true,
      body: SafeArea(
        child: LayoutBuilder(builder: (context, constraints) 
          return CustomScrollView(
            slivers: [
              SliverAppBar(
                ...
              ),
              ...
              SliverPadding(
                padding: EdgeInsets.symmetric(horizontal: 16.0),
                sliver: ValueListenableBuilder(
                  valueListenable: ExtensionBox.box.listenable(keys: [_extensionUuid]),
                  builder: (ctx, Box<Extension> box, child) 
                    List<CardModel>? cardsList = box
                        .get(_uuid)!
                        .cards
                        ?.where((card) => _isCardPassFilters(card))
                        .cast<CardModel>()
                        .toList();

                    var sortedList = _simpleSortCards(cardsList);

                    context.read<ShowingCardsProvider>().setAll(sortedList);

                    return _buildCardListGrid(sortedList);
                  ,
                ),
              ),
            ]
          );
        ),
      ),
    );
  

【问题讨论】:

【参考方案1】:

这确实是因为我正在使用ValueListenableBuilder,并且在构建小部件时,notifyListeners 被调用(进入我的提供程序)。

我的修补程序是这样做的:

return Future.delayed(
  Duration(milliseconds: 1),
  () => context.read<ShowingCardsProvider>().setAll(list),
);

不是很漂亮,但很管用?

如果你有更优雅的方式,欢迎评论!

【讨论】:

以上是关于提供者:在构建期间调用的 setState() 或 markNeedsBuild()的主要内容,如果未能解决你的问题,请参考以下文章

“在构建期间调用 setState() 或 markNeedsBuild()”错误尝试在消费者小部件(提供程序包)内的导航器中推送替换

错误:在构建期间调用了 setState() 或 markNeedsBuild()

Flutter:在构建期间调用 setState() 或 markNeedsBuild()

在构建期间调用 setState() 或 markNeedsBuild() - Flutter

Flutter:在构建期间调用 setState() 或 markNeedsBuild()

在构建 CupertinoTabScaffold 期间调用 setState() 或 markNeedsBuild()