在构建 ItemCard(dirty) 时抛出了以下断言:在构建期间调用了 setState() 或 markNeedsBuild()

Posted

技术标签:

【中文标题】在构建 ItemCard(dirty) 时抛出了以下断言:在构建期间调用了 setState() 或 markNeedsBuild()【英文标题】:The following assertion was thrown building ItemCard(dirty): setState() or markNeedsBuild() called during build 【发布时间】:2021-09-09 16:40:16 【问题描述】:

我是 Flutter 的新手,我正在尝试构建一个在线购物应用程序作为我的毕业设计。

每次我运行应用程序时,它都会直接进入“项目卡”方法并通过它进入“详细信息屏幕”,即使它应该只在按下导航器小部件时才会去那里。

它还将物品卡标记为脏孩子(我不太明白这意味着什么以及如何将其恢复为正常孩子)。

   Error message: The following assertion was thrown building ItemCard(dirty):
setState() or markNeedsBuild() called during build.

我希望我对错误的解释足够好。这是代码, 首先是 Body 类,然后是 Item Card 类,然后是 Details Screen 类:

    class Body extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: kDefaultPaddin),
          child: Text(
            "Mobiles",
            style: Theme.of(context)
                .textTheme
                .headline5!
                .copyWith(fontWeight: FontWeight.bold),
          ),
        ),
        Categories(),
        Expanded(
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: kDefaultPaddin),
            child: GridView.builder(
                itemCount: productz.length,
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 2,
                  mainAxisSpacing: kDefaultPaddin,
                  crossAxisSpacing: kDefaultPaddin,
                  childAspectRatio: 0.75,
                ),
                itemBuilder: (context, index) => ItemCard(
                      productz: productz[index],
                      press: () => Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (context) => DetailsScreen(
                              productz: productz[index],
                            ),
                          )),
                    )),
          ),
        ),
      ],
    );
  


class ItemCard extends StatelessWidget 
  final Productz productz;
  final Function press;
  const ItemCard(
    Key? key,
    required this.productz,
    required this.press,
  ) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return GestureDetector(
      onTap: press(),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Expanded(
            child: Container(
              padding: EdgeInsets.all(kDefaultPaddin),

              decoration: BoxDecoration(
                color: Colors.white12,
                borderRadius: BorderRadius.circular(16),
              ),
              child: Hero(
                tag: "$productz.id",
                child: Image.asset(productz.item_image),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: kDefaultPaddin / 4),
            child: Text(
              // products is out demo list
              productz.item_name,
              style: TextStyle(color: kTextLightColor),
            ),
          ),
          Text(
            "\$$productz.item_price",
            style: TextStyle(fontWeight: FontWeight.bold),
          )
        ],
      ),
    );
  


class DetailsScreen extends StatelessWidget 
  final Productz productz;

  const DetailsScreen(Key? key, required this.productz) : super(key: key);
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      // each product have a color
      backgroundColor: Colors.white12,
      appBar: buildAppBar(context),
      body: Body(productz: productz),
    );
  

  AppBar buildAppBar(BuildContext context) 
    return AppBar(
      backgroundColor: Colors.white12,
      elevation: 0,
      leading: IconButton(
        icon: Icon(Icons.arrow_back,
          size: 30,
          color: Colors.white,
        ),
        onPressed: () => Navigator.pop(context),
      ),
      actions: <Widget>[
        IconButton(
          icon: Icon(FontAwesomeIcons.search),
          onPressed: () ,
        ),
        IconButton(
          icon: Icon(FontAwesomeIcons.shoppingCart),
          onPressed: () ,
        ),
        SizedBox(width: kDefaultPaddin / 2)
      ],
    );
  

【问题讨论】:

【参考方案1】:

正在立即调用GestureDetector 中的onPress 函数。

有两种方法可以解决问题。

    通过删除() 删除对函数的调用 将 press 函数包装在一个匿名函数中,以便稍后用户实际执行操作时调用我,这通常在需要评估变量时完成,例如在 @987654325 的 onChanged 处理程序中@ 或 TextFormField

检查下面的代码sn-ps。

方法一的例子。

@override
  Widget build(BuildContext context) 
    return GestureDetector(
      onTap: press,
      child: ...
   )

方法二示例:

@override
  Widget build(BuildContext context) 
    return GestureDetector(
      onTap: () => press(),
      child: ...
   )

【讨论】:

这应该也可以,我添加了一个 Future Delayed 实例 @Rohan 我已经尝试过你的第一个解决方案,它显示以下错误消息:“参数类型 'Function' 不能分配给参数类型 'void Function()?'。” @HassanWaqqaf 第二种解决方案或我的回答应该有效 @Rohan 您是否介意将其添加到您的答案中:“以前,press() 将结果传递给onTap,但我们需要将function (closure) 传递给onTap,当执行,调用press()" @HassanWaqqaf 是的,只需更新您的ItemCard 类变量以匹配类型,即使press 成为'void Function()?' 类型【参考方案2】:

将其推迟到下一个刻度将起作用 -

上一个

@override
  Widget build(BuildContext context) 
    return GestureDetector(
      onTap: press();
      child: ...
   )

改为:

@override
  Widget build(BuildContext context) 
    return GestureDetector(
      onTap: Future.delayed(Duration.zero, () async 
             press();
             ),
      child: ...
   )

【讨论】:

我已经尝试过您的解决方案,出现此错误消息:“参数类型 'Future' 无法分配给参数类型 'void Function()?'。” @HassanWaqqaf 你到底尝试了什么? 这个:"onTap: Future.delayed(Duration.zero, () async press(); )," @HassanWaqqaf 你能在 press() 之前尝试使用await吗?在我的代码中 @anirudh 错误消息仍然存在..这个空安全的事情让我很紧张..

以上是关于在构建 ItemCard(dirty) 时抛出了以下断言:在构建期间调用了 setState() 或 markNeedsBuild()的主要内容,如果未能解决你的问题,请参考以下文章

颤振| ExpansionTile属性“children”在扩展时抛出了Bottous Overflowed问题

必须向 Text 小部件提供非空字符串 - 颤振

以下 _TypeError 被抛出构建 TestClass(dirty, dependencies:

Flutter导航到新页面时抛出错误

应用程序在模拟器中运行但不在实时设备中请解决此问题[关闭]

Spring / Hibernate - 删除实体时抛出 StaleStateException