isa
isa

Reputation: 427

Riverpod FutureProvider.family returns Null

I have a FutureProvider with Family parameters as below:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class I_Rem_Params {
  final String adminID;
  final String companyID;
  final int month;
  I_Rem_Params(
      {required this.adminID, required this.companyID, required this.month});
}

final iRemReportsFamily =
    FutureProvider.family<double, I_Rem_Params>((ref, iremparams) async {
  final db = FirebaseFirestore.instance;
  final admins = db.collection("Admins");
  final admin = admins.doc(iremparams.adminID);
  final companies = admin.collection("Companies");
  final company = companies.doc(iremparams.companyID);
  final imports = company.collection("Imports");
  final getImports = await imports.get();
  final val = getImports.docs.length.toDouble();
  print("value at provider : " + val.toString());
  return val;
});

I am printing the value before sent by FutureProvider as below:

value at provider : 2

I am getting and printing the AsyncValue at widget side as below:

AsyncValue<double> juneTotalValue = ref.watch(iRemReportsFamily(
    I_Rem_Params(
        adminID: adminID!, companyID: widget.companyID, month: 5)));

print("value at widget : " + juneTotalValue.value.toString());
print("runtimetype at widget : " + juneTotalValue.runtimeType.toString());

AsyncValue printed as below on widget side:

value at widget : null
runtimetype at widget : AsyncLoading<double>

And injecting the AsyncValue as follows:

....... children: [
                        juneTotalValue.when(
                            data: (data) => Text(data.toString()),
                            error: (error, stack) => Text(error.toString()),
                            loading: () => const CircularProgressIndicator()),
                        const SizedBox(
                          height: 38,
                        ),........

Handling of AsyncValue not display value of 2 sent by FutureProvider but only display loading widget of CircularProgressIndicator().

QUESTION: Why AsyncValue is Null despite there is a number sent by FutureProvider ?

Upvotes: 0

Views: 761

Answers (2)

Code on the Rocks
Code on the Rocks

Reputation: 17576

This mainly has to do with how you are creating your FutureProvider.family.

Since the .family modifier creates a new provider for each unique value that is passed to it, you need to confirm that the hashcode of the input value is the same each time you call the provider. If it's not, a new provider will be created each time. If you're using ref.watch, you can get caught in a loop:

  1. ref.watch creates FutureProvider1 (using input "1")
  2. When FutureProvider1 completes, it triggers the ref.watch line again
  3. ref.watch creates FutureProvider2 (using input "2")
  4. When FutureProvider2 completes, it triggers the ref.watch line again
  5. Repeat

This is also pointed out in the Parameter restrictions section of the Riverpod docs. In general, you should create your .family providers using a primitive data type (like int, bool, double, or string).

If you need to use something else, then you'll need to override the hashcode method of your object using a package like equatable.

class Person {
  const Person(this.name);

  final String name;

  @override
  bool operator ==(Object other) =>
    identical(this, other) ||
    other is Person &&
    runtimeType == other.runtimeType &&
    name == other.name;

  @override
  int get hashCode => name.hashCode;
}

Upvotes: 1

isa
isa

Reputation: 427

Randal's solution has solved the problem.

Upvotes: 0

Related Questions