flutterdartflutter-futurebuilder

Difficulty updating UI after removing item from list in Flutter using FutureBuilder and setState


I'm facing an issue with updating the UI in my Flutter app after removing an item from a list. I'm using a FutureBuilder to fetch data asynchronously, and I want to allow users to remove items from a list of favorites. However, when I call setState to remove an item from the list and update the UI, it doesn't reflect the changes.

List<Favorite> favorites = [];

// Use FutureBuilder to fetch the list of favorites.
FutureBuilder(
  future: placeBloc.getFavorites(),
  builder: (BuildContext context, AsyncSnapshot<List<Favorite>> favListSnapshot) { 
    if(favListSnapshot.hasData){
      // Store the list of favorites in the variable.
      favorites = favListSnapshot.data!;
      return Expanded(
        child: ListView.builder(
          itemCount: favorites.length,
          itemBuilder: (context, index){
            return GestureDetector(
              onTap: () {
                // Remove favorite from the list.
                setState(() {
                  favorites.removeAt(index);
                });
                // Remove favorite from the database...
              },
              child: Card(
                // Card details...
                child: Container(
                  // Container details...
                  child: Row(
                    children: [
                      // Widget details...
                      GestureDetector(
                        onTap: () {
                          // Remove favorite from the list.
                          setState(() {
                            favorites.removeAt(index);
                          });
                        },
                        child: SizedBox(
                          width:30,
                          child: Image.asset("assets/images/heartBlack.png",width:25,height:25),
                        ),
                      )
                    ],
                  ),
                )
              ),
            );
          }
        )
      );
    } else {
      // Handle loading state...
    }
  }
)

I've also verified that the FutureBuilder correctly fetches the list of favorites, and there are no errors or exceptions thrown in the process.

Any suggestions on how to fix this issue would be greatly appreciated!


Solution

  • The problem is you’re removing items from a variable that is inside FutureBuilder. When you call setState your entire widget is being rebuild, i.e. build() is called. Therefore after setState FutureBuilder is rebuilt and favorites are fetched again, so your changes are not reflected. In other words your changes are replaced with snapshot from FutureBuilder. To change it, i would suggest moving fetching elements from FutureBuilder to initState for example:

    List<Favorite>? favorites;
    
    @override
      void initState() {
        super.initState();
        getFavorites().then(
           (value) => setState(() {
              favorites = value;
           }),
        );
    
      }
    

    in this example you can handle build method in the way that you show loading indicator when favorites is null (it has not been fetched yet). Then you can call setState again when removing element from the list and handle your logic there.

    Other solution, useful when you need BuildContext to fetch your favorites is to move your ListView.builder to another widget and pass favorites as an argument which you will then set in initState and then operate only on this copy of your list. Calling setState on one widget will not affect parent widget tree.