0

So I have a Stateful Widget which has a List variable I want to update from the API call. My issue is that the List is empty even after I do the fetchItems() in the initState().

How can I then update the itemsList with the content of the fetchItems function? Isnt the function suppose to update itemsList if I use setState().

class _ItemsWidgetState extends State<ItemsWidget> {
        
  List<ItemsModel> itemsList = [];
  void initState(){
    fetchItems();
  }
    
  fetchItems() async {
    final response = await http.get(url);
    
    if (response.statusCode == 200) {
        final fetchedItems = json.decode(response.body);
        for (var item in fetchedItems) {
            ItemsModel item = ItemsModel.fromJson(item);
            setState(() {
                itemsList.add(item);
            });
      }
    } else {
         throw Exception('Failed to load items');
    }
}
dianesis
  • 333
  • 4
  • 17
  • 1
    As an optimization just call setState once below the `for`, that way you don't rebuild every few miliseconds on each deserialized item. – croxx5f Oct 22 '21 at 15:47
  • Right I can create a temp list inside the function but that still does not answer my question of why is the itemsList not updating after the function call. – dianesis Oct 22 '21 at 15:48

2 Answers2

3
  • Avoid calling setState inside loops, call it after your task has done.
  • Always call super.initState and mark initState as overrided
class _ItemsWidgetState extends State<ItemsWidget> {
        
  List<ItemsModel> itemsList = [];

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

    fetchItems();
  }
    
  fetchItems() async {
    final response = await http.get(url);
    
    if (response.statusCode == 200) {
      final fetchedItems = json.decode(response.body);
 
      for (var item in fetchedItems) {
          ItemsModel item = ItemsModel.fromJson(item);

          /// Remove from setState
          itemsList.add(item);
      }
      
      /// Tells to Flutter that now something has changed
      setState(() {});
    } else {
         throw Exception('Failed to load items');
    }
}
Alex Rintt
  • 1,618
  • 1
  • 11
  • 18
  • So fetchItems is a json object which I am decoding and that's why I do a loop so I can get each object from the json. – dianesis Oct 22 '21 at 15:58
  • your "json object" is literally a object or a json array object? – Alex Rintt Oct 22 '21 at 16:05
  • So this is what the api returns, [{"ID":3,"Username":"test","Name":"test","Price":"2"},{"ID":4,"Username":"test","Name":"test2","Price":"3"},{"ID":5,"Username":"test","Name":"test1234","Price":"6",},{"ID":6,"Username":"test","Name":"test1234","Price":"111"}] – dianesis Oct 22 '21 at 16:34
  • So I guess with that return I can iterate of it no? – dianesis Oct 22 '21 at 16:36
  • looks ok, so how are you building your UI on your build method? Looks like the error is not in `fetchItems` method – Alex Rintt Oct 22 '21 at 16:56
  • Also, you can check if your API returns statusCode = 200, because if it returns a different statusCode, the "fetchItems" do nothing except the API call – Alex Rintt Oct 22 '21 at 16:58
  • It does return a 200 Status. So this is okay. Well I have a bottomnavigator and when click in it it should Build the Widget which is a Scaffold and creates a Listview. The issue is that the itemsList is empty I think. You think is because initState() load before the Build and I have to wait for the fetch items? – dianesis Oct 22 '21 at 17:16
  • I realize now that you are not calling super.initState. So you need to call it before any code in your initState, I've updated my answer, please double check – Alex Rintt Oct 22 '21 at 18:08
  • Why is this necessary? – dianesis Oct 22 '21 at 18:37
0

First check fetchedItems is a list type.

   class _ItemsWidgetState extends State<ItemsWidget> {
            
      List<ItemsModel> itemsList = [];
      void initState(){
        fetchItems();
      }
        
      fetchItems() async {
        final response = await http.get(Uri.parse(url));
        
        if (response.statusCode == 200) {
            final fetchedItems = jsonDecode(response.body);
            for (var item in fetchedItems) {
                ItemsModel item = ItemsModel.fromJson(item);
                setState(() {
                    itemsList.add(item);
                });
          }
        } else {
             throw Exception('Failed to load items');
        }
    }
Hasib Akon
  • 580
  • 6
  • 16
  • So fetchItems is a json object which I am decoding and that's why I do a loop so I can get each object from the json – dianesis Oct 22 '21 at 16:04
  • 1
    Here, the First time it is decoded as a list. Then you just loop it and stored to a list .thats fine. You can just check using Future.deleay(Duration(second : 1)).then({ setState((){itemList.add(item)}) }) .Hope you will understand the concept . – Hasib Akon Oct 22 '21 at 16:40