ChangeNotifierProxyProvider builder vs update issue - flutter

i was using provider: ^3.0.0 in which it has ChangeNotifierProxyProvider parameters 'builder' in which i was providing a data. Now provider version is changed and now its updated version is provider: ^4.0.4 and it does not have 'builder' function now it has create and update functions. Kindly tell me, what's the logic behind the create and update.
I think crates runs only first time and updates runs every time after first time?
Am i right! But i have an issue, i have to pass some data to the next class in a parameter.
See my code
ChangeNotifierProxyProvider<Auth, Shops>(
create: (ctx)=> Shops('778b2f743f2aebd4d73d2431881a88ba54c53c01', []),
update: (ctx, auth, prevShop)=> Shops(auth.token, prevShop.items),
),
I wanna pass the authToken to the Shop Class, in update this data can be fetched from that auth object but in create what should i do?
And i wanna pass the list of shops as a second argument in shop class, which will be the list of Shops fetched from my server, but here because i don't have and reference so i have to pass an empty list in create.
Which means when page is loaded first time there were no list of shops and when i again open same page then the shop list will be listed on the screen.
kindly help me out to clear this issue.

Do it like this
ChangeNotifierProxyProvider<Auth, Shops>(
create: (ctx) => Shops('', []),
update: (ctx, auth, prevShop) => Shops(
auth.token.toString(),
prevShop == null ? [] : prevShop.items)
),

How about doing this
ChangeNotifierProxyProvider<Auth, Shops?>(
create: (_) => null,
update: (ctx, auth, prevShop) => Shops(
auth.token.toString(),
prevShop == null ? [] : prevShop.items)
),

I also encountered the same problem. I searched the documentation and found the solution.
You need to define the function update() in the Shops() class which takes in your arguments:
auth.token and prevShop.items in that and you need to update anything you want in that update function.
ChangeNotifierProxyProvider<Auth, Shops>(
create: (ctx)=> Shops(),
update: (ctx, auth, prevShop)=> prevShop..update(auth, prevShop.items),
),
We use ..update(auth.token, prevShop.items) to return the same Shops() widget.

Related

The named parameter 'bloc' isn't defined - bloc provider

I've read the flutter-bloc documentation and I really have no idea what to do anymore. Someone to help?
error bloc provider
Probably you didn't import the Bloc package into this file.
Try create: instead of bloc:
BlocProvider<UserBloc>(
create: (context) => UserBloc(),
child: Container(),
);

How to pass an existing repository instance to the next page in Flutter using the flutter_bloc package?

I have the following code that passes a bloc to the next page
Navigator.of(context).push(
MaterialPageRoute<CreateFeedSelectClass>(
builder: (_) => BlocProvider.value(
value: BlocProvider.of<TeacheractivityfeedBloc>(context),
child: CreateFeedSelectClass(imageStringList: state.selectedImages, imagePathList: state.selectedImagePaths, classList: state.classList,))
)
);
I would like to pass this repository that was already created in this page before the build function
TeacherRepository _teacherRepository = TeacherRepository();
In the example from flutter bloc (https://pub.dev/packages/flutter_bloc)
there is only a way to create a new instance, I want to pass the existing instance instead of creating a new one:
RepositoryProvider(
create: (context) => RepositoryA(), //----->
child: ChildA(),
);
instead of
create: is there any way to do something like value: _teacherRepository like how we do it with BlocProvider.value(value:....) ?
Actually there is a named constructor value available for RepositoryProvider which you can use.
RepositoryProvider.value(
value: repository,
child: Container(),
);

ChangeNotifierProxyProvider not initiated on build

I'm trying to understand multiproviders in Flutter. In my App, one Provider need to change based on a value from an other Provider.
AuthProvider gets initiated higher up in the widget tree on build. Works like a charm with automatic sign in if possible...
In a lower placed widget, I try to initiate two other Providers. One, WhatEver, is not depended on other data and gets initiated on build like it is supposed to using ChangeNotifierProvider.
ProductList however is depended on AuthProvider. If log in status is changed, the ProducList should update accordingly.
In my attempts, I've found out, ie found on SO, that ChangeNotifierProxyProvider is the right way to go. But when I run the App, it seems like the 'create'-part of ChangeNotifierProxyProvider is not initiated when the widget gets build. It seems like the ProductList provider is not initiated until it's read or written to.
What have I misunderstood using MultiProviders and ChangeNotifierProxyProvider?
return MultiProvider(
providers: [
ChangeNotifierProvider<WhatEver>(create: (context) => WhatEver()),
ChangeNotifierProxyProvider<AuthProvider, ProductList>(
create: (_) => ProductList(Provider.of<AuthProvider>(context, listen: false)),
update: (_, auth, productList) => productList..reloadList(auth)
),
],
The ProductList looks like this:
final AuthProvider _authProvider;
static const String _TAG = "Shop - product_list.dart : ";
ProductList(this._authProvider) {
print(_TAG + "ProductList Provider initiated");
reloadList(this._authProvider);
}
void reloadList(AuthProvider authProvider) {
print(_TAG + "ProductList reload started");
if (authProvider.user==null) {
print(_TAG + "ProductList: _authProvider == null");
_loadBuiltInList();
} else {
print(_TAG + "ProductList: user = " + authProvider.user.displayName);
_loadFirestoreList();
}
}
I have code that does this:
ChangeNotifierProxyProvider<AuthService, ProfileService>(
create: (ctx) => ProfileService(),
update: (ctx, authService, profileService) =>
profileService..updateAuth(authService),
),
My ProfileService() does not rely on AuthService being available when it is constructed. The code works fine :)
The ChangeNotifierProxyProvider documentation explicitly describes this approach:
Notice how MyChangeNotifier doesn't receive MyModel in its constructor
anymore. It is now passed through a custom setter/method instead.

How to combine multiple providers in Flutter

I am new to Flutter development.
I am building application where once users login they are shown list of posts.
If the user is not login still they are shown some random post.
I got parts of the application various posts in the internet.
This is what I did
class TestApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
Provider<AuthBase>(
create: (context) => Auth(),
),
StreamProvider<User>.value(
value: Auth().onAuthStateChanged,
),
ProxyProvider<User, Database>(
update: (BuildContext context, User user, Database db) {
return user == null
? FirestoreDatabase(uid: null)
: FirestoreDatabase(uid: user.uid);
}),
ChangeNotifierProxyProvider<Database, PostProvider>(
create: (context) => PostProvider(),
update: (ctx, database, previousProvider) {
print("at ChangeNotifierProxyProvider $previousProvider");
return previousProvider.update(database);
},
),
],
child: MaterialApp(
title: 'Test Project',
home: LandingPage(),
),
);
}
My idea is;
if the user is logged in StreamProvider<User>.value will give that user to
ProxyProvider<User, Database> and it will create database with that user.
And that database in turn will be used by ChangeNotifierProxyProvider<Database, PostProvider> to create the provider that actually get posts. It uses the database to get the posts.
I noticed even if the user is logged in at the start I get a null value for the user then immediately i get the actual user.
In the landing page, I only have the following line and it generate an error
final provider = Provider.of<PostProvider>(context);
I noticed the cause for the error was this line;
previousProvider.update(database);
First time time Postprovider constructor and update methods get called without any problem. (here we get null user)
When the FirestoreDatabase get created with the actual user "previousProvider" is null.
This is the reason for the error.
Not sure why this is happening or how to fix it.
Is there a better way of doing this?
Initially getting a null value even when there is a logged in user may be the reason. How to prevent it?
I will try to explain your code a bit so we are on the same page
Provider<AuthBase>(
create: (context) => Auth(), //this subscribe an Auth Class to the provider
),
StreamProvider<User>.value(
value: Auth().onAuthStateChanged,
/// This subscribe a stream from another Auth Class instance
/// Unless Auth its a singleton class, this is not related to the previous Provider
/// and changes to Provider<AuthBase> won't affect this Stream
),
I noticed even if the user is logged in at the start I get a null
value for the user then immediately i get the actual user.
That happens when using Stream, while the first value is captured (sometimes is delayed a tick) its null, you can use initialData parameter if you know the first value while the stream subscription is done
Finally
ChangeNotifierProxyProvider<Database, PostProvider>(
create: (context) => PostProvider(),
update: (ctx, database, previousProvider) {
print("at ChangeNotifierProxyProvider $previousProvider");
return previousProvider.update(database);
},
),
update expects to return a value of type PostProvider, but you're returning whatever the method previousProvider.update(database) returns (which I think it just updates some inner variable or something, I believe it's some void method maybe?)
Change the update like this
update: (ctx, database, previousProvider) {
print("at ChangeNotifierProxyProvider $previousProvider");
return previousProvider..update(database);
/// It's the same as writing this
/// previousProvider..update(database);
/// return previousProvider;
},

Flutter Better way to add Providers in main.dart file

In main.dart file I always have to add the same thing with different class name to make things works, here is an example.
MultiProvider(
providers: [
ChangeNotifierProvider<ProductDataProvider>(
create: (_) => ProductDataProvider()),
ChangeNotifierProvider<AuthenticationProvider>(
create: (_) => AuthenticationProvider()),
],
child: Container())
If we have 20 providers let's say then there is a lot duplicate code there right. Is any work around this?
See, if it is about initializing your provider in your main.dart, I am afraid, you have to do it, cos it need those.
For any duplicates, you can make use of some short tricks and get going.
Create an Array consisting of all your ChangeNotifiers, like in this case: ProductDataProvider and AuthenticationProvider
List<ChangeNotifier>_providersArray = [ProductDataProvider, AuthenticationProvider];
Now, when you have the array, add it to the array which adds the ChangeNotifier, to your final providers list.
// This will be your array of Providers, which you will add to Mutliprovider(providers: HERE)
List<Provider> providers = []; // make sure you have the right type of the List<>, which the `providers` in `Multiproviders` accepts
for(var provider in _providersArray){
//adding the provider name to the ChangeNotifier
providers.add(ChangeNotifierProvider<provider>( create: (_) => provider()));
}
Finally passing the providers in your Multiprovider
MultiProvider(
providers: providers,
child: Container()
)
Max to max, you will have to do the type casting for some type mismatches, and you're good to go. Let me know if that helps you in anyway.