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!
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.