I have two data models a) Product b) Jobs
I create Stream Provider in main.dart _MyAppState class (top most widget). It reads a collection from firestore.
MultiProvider(
providers: [
StreamProvider<List<Job>?>(
create: (_) => JobsProvider.readJobs(),
initialData: [],
catchError: (_, __) => null,
)
],
Based on user role, I redirect to another page which creates FutureProvider in build function
MultiProvider(
providers: [
FutureProvider<List<Product>>(
create: (_) => fetchProductsFromBase(), initialData: []),
//.. other providers
],
Now, I create a widget to show some results combining the two providers's specific fields from firestore (int 'qty' from Job data model and double 'dim_x' & 'dim_y' from Product data model) in a StatefulWidget's State class.
List<Product>? productList;
@override
Widget build(BuildContext context) {
productList = context.watch<List<Product>>();
print('NUM PRODUCTS = ${productList?.length}\n');
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Delivery Schedule',
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: Colors.black87)),
const SizedBox(
height: 15.0,
),
Selector<List<JobDetailWithID>, List<Map<String, dynamic>>>(
selector: (BuildContext context,
List<JobDetailWithID> jobs) =>
getDeliveriesByDeliveryDate(jobs, numDaysSchedule, productList ?? []),
builder: (BuildContext context, List<Map<String, dynamic>> toBeDeliveredJobs, _) {
return Wrap(
// ... My Widget UI ... toBeDeliveredJobs used in here
);
},
),
],
);
}
List<Map<String, dynamic>> getDeliveriesByDeliveryDate(
List<JobDetailWithID> jobs, int numDaysSchedule, List<Product> productList) {
List<Map<String, dynamic>> deliveries = [];
// ... Do Some Calculations and add to the empty list
// ... Part of code includes below snippet
// areaForTheDay = {
// 'delivery_date': date.add(Duration(days: i)),
// 'target': productList.length == 0
// ? 'NA'
// : GetSomeDoubleValueFromJobs()
return deliveries;
}
Problem: Print statement in above code gives zero length of product list initially. Thus Selector<List throws a _TypeError type 'String' is not a subtype of type 'num'
Please suggest how to tackle this error, so that the widget builds after it has all the data from providers and if I'm using the mentioned specific three fields correctly to minimise firebase reads.
Note: These providers are used at many other widgets and didn't notice such behaviour before.
Edit: I have posted a solution below which solves the building of this widget once data is fetched. Seeking better answers with performance optimisation.
I have been able to solve my question with riverpod as below. However, I am still facing some performance issues. More suitable answers are welcome to stop rebuilds. More details ahead.
Solution:
Enabling riverpod in my app by - Adding flutter_riverpod to my pubspec.yaml and other necessary packages mentioned in docs ( https://riverpod.dev/docs/introduction/getting_started ) & wrapping MyApp with ProviderScope
Converting my future provider into riverpod provider
Using my StreamProvider as it as because it will take some time to migrate the complete app to riverpod (will eventually do so).
And the state class of the widget in question is written as -
Problem left to solve is: This widget (MyWidget) is part of a parent StatefulWidget - Scaffold. Any other widget rebuild in this Scaffold triggers rebuild of this widget and I'm assuming it does not fetch data from firestore again and again (this would be more disastrous) as per concepts I learned from docs - correct me if I'm wrong. The MyWidget rebuild twice even on closing the parent scaffold page. Please post better answers on how to solve it completely. Pardon me if I missed somethings in riverpod docs as it was a lot to grasp.