I'm building a Flutter app, and have a page with a table that is populated with data. I load the data like so:

class _AccountMenuState extends State<AccountMenu> { {
  List<Account> accounts;

  Future<List<Account>> getAccounts() async {
    final response = await http.get('http://localhost:5000/accounts/' + globals.userId);
    return jsonDecode(response);
  }

  setAccounts() async {
    accounts = await getAccounts();
  }

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

This works as expected when hot reloading the page, but when I route to this page via MaterialPageRoute,

like so: Navigator.push(context, MaterialPageRoute(builder: (context) => AccountMenu()));

then the data is not there.

What am I missing? I thought initState() gets called whenever a page loads?


Solution 1: gordonturibamwe

initState does not await. It only loads functions before the widget builder but it does not await. you need to await loading widgets with data until accounts.length is not empty. Show loading widget while data still loads or use FutureBuilder

List<Account> accounts;

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

@override
Widget build(BuildContext context) {
 accounts.length > 0 ? SHOW_DATA_HERE : LOADING_WIDGET_HERE
}


Solution 2: Akash Mehta

initState() will not wait for setAccounts() to finish execution. In the method setAccounts() call setState after loading data.

 setAccounts() async {
    accounts = await getAccounts();
    setState((){});
  }


Solution 3: MJ Montes

You cannot do setState inside initState directly but you can wrap the initialization inside a PostFrameCallback to make sure that the initState lifecycle of the Widget is done.

    class _AccountMenuState extends State<AccountMenu> { {
      List<Account> accounts;

      Future<List<Account>> getAccounts() async {
        final response = await http.get('http://localhost:5000/accounts/' + globals.userId);
        return jsonDecode(response);
      }

      setAccounts() async {
        accounts = await getAccounts();
        setState(() {})
      }

      @override
      void initState() {
        WidgetsBinding.instance.addPostFrameCallback((_) => setAccounts());
        super.initState();
      }
    }