1

I have a stream provider that depends on a request to resolve. However the execution steps put at the first await statement, causing the response to be null. Which throws an error

The request provider

final postProvider = FutureProvider.family.autoDispose(
  (ref, Tuple2<String?, Map<dynamic, dynamic>?> info) async {
    var path = info.item1 ?? '';
    var payload = info.item2;

    final url = backendUrl().replace(path: path);
    return await http.post(
      url,
      headers: {
        'X-FIREBASE_TOKEN':
            await ref.read(authProvider).currentUser!.getIdToken() //this is where execution steps out
      },
      body: payload != null ? jsonEncode(payload) : null,
    );
  },
);

the StreamProvider:

final chatProvider = StreamProvider.autoDispose((ref) {
  final chatId = ref.watch(chatIdProvider);

  if (chatId == null) {
    final resp = ref
        .watch(postProvider(const Tuple2('create-chat', null)))
        .value!; //this evaluates to null.

    ref.read(chatIdProvider.notifier).state = jsonDecode(resp.body)['chat_id'];
  }

  final uid = ref.watch(userStreamProvider).value!.uid;

  return ref.read(docRefProvider('${uid}_chats/$chatId')).snapshots();
});

I can't use the future from the FutureProvider because that would require me to have an async callback, which would not return a Future rather than a Stream. How do I work around this?

Mudassir
  • 725
  • 6
  • 28

1 Answers1

2

What you could do is try and use yield, like the below example. The if block checks if the chatId is null, and if it is, it waits for the postProvider to resolve by using await ref.watch(postProvider(const Tuple2('create-chat', null)).last).

final chatProvider = StreamProvider.autoDispose((ref) async* {
  final chatId = ref.watch(chatIdProvider);

  if (chatId == null) {
    final resp = await ref.watch(postProvider(const Tuple2('create-chat', null)).last);

    ref.read(chatIdProvider.notifier).state = jsonDecode(resp.body)['chat_id'];
  }

  final uid = ref.watch(userStreamProvider).value!.uid;

  yield* ref.read(docRefProvider('${uid}_chats/$chatId')).snapshots();
});

more on that here https://dart.dev/language/functions#generators and here https://stackoverflow.com/a/56173833/5666202

and the last on the resp returns a Future that returns the last emitted value from the provider, which is what you seem to need in this case

Fernando Rocha
  • 2,416
  • 3
  • 15
  • 28
  • I decided to put all the future logic on a button call back. If anyone has tried this solution, please mention it and I will mark it as correct. – Mudassir May 02 '23 at 16:10