【问题标题】:Flutter ListView doesn't refresh UI with setState(), although itemCount and attached list update correctlyFlutter ListView 不使用 setState() 刷新 UI,尽管 itemCount 和附加列表正确更新
【发布时间】:2020-03-14 03:21:11
【问题描述】:

我看到很多人有非常相似的问题,但我尝试的任何方法都不起作用。

上下文

我有一个收藏的想法列表。每当我单击ideaItem 内的按钮时,它都会从列表中删除。

问题

当我删除任何ideaItem 时,屏幕上的最后一个总是被删除,而不是我点击的那个。我的 FavoriteIdeasListView 似乎正确更新了项目数,这意味着附加的列表有效,但 UI 没有重绘 ideaItems。

我已经尝试过什么

  • 一开始我直接在ideaItem 上有删除功能,我读到我应该做一个VoidCallback 并处理从列表本身删除,所以它会注意到变化。没用

  • 我也尝试过使用 Stream Builder,因此流会通知 ListView 刷新。也没用

  • 我尝试一直调用 SetState 并且它没有重新加载,它只是在 initialState 的开头构建列表。


    class FavoritesList extends StatefulWidget {
      FavoritesList({Key key}) : super(key: key);

      @override
      _FavoritesListState createState() => _FavoritesListState();
    }

    class _FavoritesListState extends State<FavoritesList> {

      List<Idea> _favorites = [];

      @override
      void initState() {
        super.initState();
        favoritesInitialState();
      }

      Future <void> favoritesInitialState() async {
        List<Idea> ideas = await IdeasDB.db.ideas();
        setState(() {
          _favorites = ideas;
        });
      }

      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text('Favorites')),
            body: Center(
              child: ListView.builder(
                itemCount: _favorites.length,
                itemBuilder: (context, index) {
                  final idea = _favorites[index];
                  return IdeaItem(
                    idea: idea,
                    onFavoriteToggle: () => deleteFromFavorites(idea),
                  );
                },
              ),
            )
        );
      }

      void deleteFromFavorites(Idea idea) async {
        await IdeasDB.db.deleteIdea(idea.url);
        List<Idea> newIdeas = await IdeasDB.db.ideas();
        setState(() {
          this._favorites = newIdeas;
        });
      }
    }

【问题讨论】:

    标签: listview flutter dart reactive-programming


    【解决方案1】:

    尝试改变

    onFavoriteToggle: () => deleteFromFavorites(index),
    

    然后

      void deleteFromFavorites( int index) async {
        await IdeasDB.db.deleteIdea(idea.url);
        setState(() {
          this._favorites.removeAt(index);
        });
      }
    

    看看它是否有效。如果是,deleteIdea() 上可能有错误。

    此外,您知道应该删除哪个项目,因此您无需等待从数据库中重新加载列表。 await IdeasDB.db.ideas();

    如果您想确保可以使用 Try catch 包装您的代码

      void deleteFromFavorites(int index) async {
        try {
          await IdeasDB.db.deleteIdea(idea.url);
          setState(() {
            this._favorites.removeAt(index);
          });
        } catch (_) {
          print('ERROR');
        }
      }
    

    【讨论】:

    • 解决方案是传递 'key' 参数。我赞成,因为优化解决方案消除了不必要的等待!谢谢!
    【解决方案2】:

    对于为什么会发生这种情况,我只能看到两种可能的选择。

    第一个很明显,您的IdeasDB.db.deleteIdea(idea.url); 没有从数据库中删除正确的想法;

    第二个不太明显,这是因为您的元素树无法识别您要删除的小部件是什么。它只发生在有状态的小部件上,就像您的 IdeaItem 一样。

    然后解决方案是为您的IdeaItem 小部件使用key 属性 像这样:

    ListView.builder(
      itemCount: _favorites.length,
      itemBuilder: (context, index) {
        final idea = _favorites[index];
        return IdeaItem(
          key: ValueKey(idea.url) // or UniqueKey()
          idea: idea,
          onFavoriteToggle: () => deleteFromFavorites(idea),
        );
      },
    ),
    

    在您的 IdeaItem 小部件中,您必须将该密钥传递给您的父级 Stateful widget,如下例所示:

    class IdeaItem extends StatefulWidget {
      final Idea idea;
      Function onFavoriteToggle;
    
      IdeaItem({Key key, this.idea, this.onFavoriteToggle}) : super(key: key);
    
      @override
      _IdeaItemState createState() => _IdeaItemState();
    }
    

    【讨论】:

    • 有效!解决方案是添加密钥,因为我的 IdeaItem 确实也是有状态的!太棒了!
    猜你喜欢
    • 2019-01-19
    • 1970-01-01
    • 1970-01-01
    • 2021-03-02
    • 2021-05-29
    • 2020-11-16
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多