3

So basically I have a Future which return the jwt I got from secure storage, and I want to assign the return to a variable let's say the variable is token. It goes kind of something like this.

Future<String> getJwt() async {
      final secureStorage = SecureStorage();
      var jwt = await secureStorage.readSecureData('jwt');
      return jwt;
    }

and I want to assign to variable, like this.

static String token = getJwt();

the code is something like this.

String? _token;

Future<String> getJwt() async {
      final secureStorage = SecureStorage();
      var jwt = await secureStorage.readSecureData('jwt');
      return jwt;
    }

void getJWT() async {
  String token = await getJwt(); 
  
}

class API {

  final token = getJWT();
  static Future<String> getData(String url) async {
    try {
      http.Response response = await http.get(Uri.parse(baseURL + url),
          headers: {
            "Content-type": "application/json",
            "Authorization": 'Bearer ' + token
          });

      return response.body;
    } catch (_) {
      return 'error';
    }
  }

  static Future<String> postData(String url, String json) async {
    try {
      http.Response response = await http.post(Uri.parse(baseURL + url),
          headers: {
            "Content-type": "application/json",
            'Authorization': 'Bearer ' + token
          },
          body: json);

      return response.body;
    } catch (_) {
      return 'error';
    }
  }
}

I already try changing the String to Future but It doesn't work, how to solve this problem? thanks in advance.

3 Answers 3

6

So you need an asynchronous function to do this. I know of 2 ways:

  1. use async/await
  2. use then

Example:

// use async await
void main() async {
  String ret = await getAbc();
  print("ret: $ret");
  // ----- result -----
  // ret: abc
}

// use then
void main2() {
  getAbc().then((String ret) {
    print("ret: $ret");
  });
  // ----- result -----
  // ret: abc
}

Future<String> getAbc() async {
  await Future.delayed(Duration(seconds: 1));
  return "abc";
}


Sign up to request clarification or add additional context in comments.

Comments

0

Since you are working with Futures, I would recommend you to separate your methods to poblate variables. Also, keep in mind that Future functions require asynchronous notations like this:

Your function

Future<String> getJwt() async {
  final secureStorage = SecureStorage();
  var jwt = await secureStorage.readSecureData('jwt');
  return jwt;
}

Future functions

late String _jwt;

setJwt(String jwt){
  _jwt = jwt;
}

Future<void> poblateJwt () async {
  await getJwt().then((value){
   setJwt(value);
  });
}

getJwtData() {
  return _jwt;
}

Now, you can call the function getJwtData and use it everywhere. The last remaining thing is use a FutureBuilder in your app and call the "poblateJwt" method only once. Like this:

class YourWidget extends StatefulWidget {
  const YourWidget({Key? key};

  @override
  State<YourWidget> createState() => _YourWidgetState();
}

class _YourWidgetState extends State<YourWidget> {
  late var _future;

  @override
  void initState() {
    _future = poblateJwt();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {

    //use this as a String value

    final jwt = getJwtData();

    return FutureBuilder(
      future: _future,
      ... rest of your  code
    );
  }


}

6 Comments

with FutureBuilder you dont need any poblateJwt / getJwtData methods, late String _jwt; etc - all you need is to set _future = getJwt(); inside initState and use it directly inside FutureBuilder
I already try this method for another project and It works like a charm, but in this project I cannot assign it like that because it's just a simple class I use for service to hit an API. So therefore I probably can't use setState or InitState. I'm thinking about using a global variable but for a simple class but I can't make it work. Any other solution?
@pskink the goal with the poblate function and set it as a future in the init state is to set an initial value to late String variable. Using this method will prevent unnecessary rebuilts because if you have a method, per say, that calls a "setState" function, this widget with rebuild and that is something you don't want most of the time. This is a good practice, specially if you are working with Provider pattern or using a Presenter or MVVM architecture.
you dont have any "unnecessary rebuilts" - just init _future = getJwt(); (without any other additional async methods) and use use it like future: _future inside FutureBuilder - thats all
@pskink could you write it as a code please.
|
0

Future<String> getJwt() async {}

as getJWT() returns a Future which indicates it will return some value (a String) in the future. This is part of asynchronous programing.

So, adding await basically says that we need to wait for the response which will be there at some point in the future.

static String token = await getJwt();

You can watch this awesome tutorial on async and wait by Flutter team

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.