14

when I use setState () the text appears in the debug console..

setState() callback argument returned a Future. The setState() method on _LoginActivityState#9cd91 was called with a closure or method that returned a Future. Maybe it is marked as "async". Instead of performing asynchronous work inside a call to setState(), first execute the work (without updating the widget state), and then synchronously update the state inside a call to setState().

   Future<void> login() async {
final formState = formKey.currentState;
if (formState.validate()) {
  formState.save();
  try {
    final response = await UserController.login({
      "username": username,
      "password": password,
    });

    if (response != null && response["success"]) {
      setState(() async {
        accessToken = response['token'];
        //print(token);
        if (accessToken != null) {
          await Http.setAccessToken("Bearer $accessToken");
        }
        print('$accessToken');
        final getMe = await AiframeworkController.getProfile();
        print('data: $getMe');
        if (getMe != null && getMe['is_verified'] == true) {
           return Navigator.pushReplacement(
                context, MaterialPageRoute(builder: (context) => MainActivity()));
        } else {
          return Center(
                child: CircularProgressIndicator(),
              );
        }
      });
    }
  } catch (e) {
    print(e.message);
  }
}

}

oceany
  • 365
  • 2
  • 5
  • 11
  • 9
    You should probably do the async code outside of the setState method and only set the state when that code has completed – Smashing Jul 09 '19 at 07:13

1 Answers1

14

setState() should be used only to set the new state of a stateful widget. You shouldn't perform async operations in it and you shouldn't return anything from it. I am assuming that 'accessToken' is the field you are changing the state of so it will be better to do all of the other operations outside the setState() and just leave 'accessToken = response['token'];' inside.

Erol Asan
  • 378
  • 2
  • 12
  • 1
    The only exception I've come across is for a re-usable FutureBuilder. You might want the Future to actually be the state, eg, a list with a refresh button that shows a spinner when pressed until loaded – The Trav Jan 01 '20 at 23:54
  • @TheTrav How would I go about updating the Future state variable used in my Futurebuilder? (Since this: `setState(() => _futureForFutureBuilder = myFuture);` throws exactly this error.. – Jimmy Jan 04 '21 at 14:36
  • @Jimmy I never ended up with a satisfactory solution. https://gist.github.com/thetrav/bca10c1fd1dd123fe5dbbd7c361aabff is the collection of components I use to deal with different async use cases. In the case of future builder i try to provide the future as a prop so the widget gets re-built when the async function is re-run – The Trav Jan 05 '21 at 21:20
  • 1
    @jimmy I should disclaim that my solution still appears to be setting the future as part of the build function, which is a no-no according to the flutter docs, however I haven't experienced any issues with it. https://github.com/flutter/flutter/issues/16218#event-3407922515 has some further discussion but it's mostly over my head – The Trav Jan 07 '21 at 20:19