Flutter ListView不会使用setState()刷新UI,尽管itemCount和附加列表已正确更新

时间:2019-11-18 17:22:14

标签: listview flutter dart reactive-programming

我看到很多人都有非常相似的问题,但是我没有尝试。

语境

我有一个最喜欢的想法列表。每当我单击ideaItem内的按钮时,它都应该从列表中删除。

问题

当我删除任何ideaItem时,屏幕上的最后一个总是被删除,而不是我单击的那个。我的FavoriteIdeasListView似乎可以正确更新项目计数,这意味着附加的List可以工作,但UI不会重绘ideaItems。

我尝试过的内容

  • 一开始,我直接在ideaItem上具有删除功能,我读到我应该做一个VoidCallback并处理从List本身的删除,因此它将注意到更改。没用

  • 我还尝试了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;
        });
      }
    }

2 个答案:

答案 0 :(得分:1)

对于这种情况,我只能看到两个可能的选择。

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

第二个不那么明显,这是因为您的元素树无法识别您要删除的小部件。仅当您使用IdeaItem时,状态状态控件才会发生这种情况。

接下来的解决方案是为key小部件使用IdeaItem属性 像这样:

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();
}

答案 1 :(得分: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');
    }
  }