Is it okay to call provider functions in main.dart Flutter - flutter

in Flutter,
I am calling provider functions to load data from database in main.dart and I saw that main.dart is calling them continuously, so I added bool to check if they called or if they are loading now to stop continuous calls, after that it started to concern me. Is this way okay? What is the better way? I don't want to add it to the first pages initstate as if user has details in SharedPreferences, I wait and send token to get different data.
Here is the calling part in main.dart file.
Checks if user has details in SharedPreferences.
Loads chats if user has details in SharedPreferences.
Connects to socket if not connected before.
If user has details, starts loading and in the first step it makes isLoadingUserForMain = false so that until it loads and gets responds it won't be able to call.
Please tell me your opinion thanks..

Look the best way of doing what you want to achieve is...
Make an Splash or middle screen of loading.
push all the asynchronous task at that Widget.
You can handle anything there.
It is not recommended to do asynchronous tasks in main function. So you need to make Material app to do the tasks..

I would have a splash screen like #Akash mentions, but I would call these methods when your provider is initialized. For example, lets say you create your providers like this at the top of your app:
runApp(MultiProvider(providers: [
Provider<DatabaseService>(
create: (_) => YourService(),
lazy: false,
),
],
child: MyApp()));
Your init logic in the question would exist in the constructor of YourService.
Now you could have a stream of userDetails that your splash screen will listen to and once it emits details go to the appropriate screen.

Related

How to reduce/optimize api call when initial a bloc

I have a navbar, change between 2 screens nested with Provider create blocs. Whenever bloc constructor called. It's call api to get data and add to the stream. So the problem here, user can spam switch between 2 screens and make the bloc dispose and init => api was called multiple times.
Class Bloc1 {
const Bloc1(){
data = await fetch() //Call api
stream1.add(data) //Then add to stream
}
}
I have tried the lock. But it does not work because when recreate, the lock is recreate too -> useless.
Class Bloc1{
var lock = false;
const Bloc1(){
if(lock == false) {
data = await fetch() //Call api
stream1.add(data) //Then add to stream
}
}
}
In my opinion, the issue you are mentioning is a kind of a border case where the user will have an aggressive behavior with the switch.
That being said, I think you should clarify a few points:
Do you really want to change the switch behavior to avoid this scenario?
Does it make sense to fetch new data every time the user switches tabs? I mean, does the data change that often? Because if the data does not change, maybe it does not makes sense to make a new request to the API at that point, and you should consider fetching this data at some other point.
I think there is no way to avoid this scenario if you instantiate/dispose your bloc every time the user switches screens (unless you save the lock or previously retrieved data outside the bloc, so next time you instantiate this bloc you can provide this value via the constructor, and this way you can avoid making the API request).
Depending on your Bloc logic, a solution could be that you instantiate the Bloc above these two screens, by doing this the Bloc will not be disposed once you switch screens and therefore it won't be instantiated again. Take into account that this approach will make the Bloc to be alive no matter how many times the user switches screens, and it is possible that this is something that you want to avoid.

updateDisplayName in action without reloading simulator

In my code, I have firebase auth and I get the current user as:
User user = FirebaseAuth.instance.currentUser!;
To display the user name in a Text, just use Text(user.displayName)
To test the update functionality, I created a simple button and on onPressed I have
user.updateDisplayName('Test').then((_) =>user.reload());
How to "notify" the Text that the data has changed and change it without needing to reload the simulator?
--> this code is in a drawer
Since you're using Flutter, you'll need to store the value you want to re-render in the State of a stateful widget, call setState() when the value is updated, and then render it from there in your build method.
I recommend checking the documentation on StatefulWidget for an example of this, and more explanation than I can ever repeat here.

MaterialApp init function/widget with proper context

Like every other app that I created I have some boilerplate code that I need to execute before loading the application:
session check
store hydration
route change listener
user session listener
...
This code, more often than not, requires a BuildContext context to be available. I cannot use the context that sits at the same level with MaterialApp due to complaints from flutter so I need to go deeper 1+ levels in order to grab a context from a descendant. That descendant is my home route and it obviously fails when you navigate away.
What is a proper place to grab a context and initiate my watchers app wide? Where would you continuously watch for a navigation change for example?

Flutter: Update specific screen using provider that's consumed in multiple screens

I have a typical CRUD operation task: (List Sites, Add Site, ...)
I created a SitesProvider. In the same provider, I added 2 methods for add and edit. I was thinking to use the same provider in the 2 screens (ListSites and AddEditSite)
In the ListSites screen, it works fine. Here is the problem:
I open the AddSite screen by clicking the AddButton in the ListSites screen
Hit submit (did not enter data, simulating error case)
The error gets displayed in the ListSites screen, not in the AddSite screen.
It makes sense. They both use the same provider, both screens are on the stack. It seems that the first one only consumes the state update and displays the error.
I use MultipleProviders approach that wraps the MaterialApp with all providers in the app.
Can we fix that without creating separate providers for each of the 2 screens?
EDIT:
I used provider.removeListener in the ListSites screen right before I open the AddEdit and it shows the error in the correct screen now. I still have to do some other tweaks to get it back to listen after I add. Not efficient I think but it is a step.
I ended up doing that:
Added Another Field in the provider (stateType: list/addedit)
Change the type per the screen I'm currently in
provider.stateType = UIStateType.add_edit;
await Navigator.push(context,
MaterialPageRoute(builder: (context) => AddEditSiteScreen()));
provider.stateType = UIStateType.list;
in build(), I check for the type
sitesProvider = Provider.of(context);
if (sitesProvider.stateType != UIStateType.add_edit) return Container();

How can I notify other screen to re-fetch when there is a mutation?

I have some api that are going to change the data in the backend.
Each screen has its own state, I start fetch the data in the initState, and store it to the state once available.
The problem is how can I notify the screen in the backstack to refetch when I know their data in the state is now outdated? They won't be refetch when I am back to them since the initState won't be called again.
I come from React Native, where there is react-query, which will refetch and rebuild the screen when I invalidate the corresponding cache. Is something similar available in flutter?
You can try this, please put this on your first screen.
Navigator.of(context).pushNamed('/someRoute').then((completion){
your initstate function
});
Ref : https://api.flutter.dev/flutter/widgets/Navigator/push.html
If you need to notify more then one screens, use https://pub.dev/packages/flutter_bloc (There are other options) instead.