when using setState () appears setState () callback argument returned a Future
Asked Answered
B

2

15

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);
  }
}

}

Bunyan answered 9/7, 2019 at 7:9 Comment(1)
You should probably do the async code outside of the setState method and only set the state when that code has completedOgata
D
15

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.

Delly answered 9/7, 2019 at 8:18 Comment(4)
The only exception I've come across is for a re-usable FutureBuilder. You might want the Future<T> to actually be the state, eg, a list with a refresh button that shows a spinner when pressed until loadedCloseup
@TheTrav How would I go about updating the Future<T> state variable used in my Futurebuilder? (Since this: setState(() => _futureForFutureBuilder = myFuture); throws exactly this error..Keare
@Keare I never ended up with a satisfactory solution. 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-runCloseup
@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. github.com/flutter/flutter/issues/16218#event-3407922515 has some further discussion but it's mostly over my headCloseup
A
1

The error message is self-explanatory.

In your code, you are using the async keyword:

 setState(() async {
        accessToken = response['token'];

However, if you have asynchronous operations, you should handle them outside of setState() and then call setState() to update the UI with the new state.

You can usually use MyFuture.whenComplete:

_myFuture()
    .whenComplete(() => setState(() {}));
Arbor answered 3/1 at 1:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.