Call api after bage build in getx - flutter-getx

Im using getx and i want to call api after bage build, because this api its not necessary part of the page build.. What i know is this way
#override
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
});
}
But what about getx best way ?

the Getx package offers lifecycle methods that are very convenient in you're cases, what you need here is to use the onReady(), which is called one frame after the onInit() is executed, you can say that its equivalent to the:
#override
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
// Here is the code which will be executed exactly after initState using StatefulWidget
});
}
you can use onReady() like this:
class TextController extends GetxController {
#override
void onInit() {
/*...*/
}
void onReady() {
// Here is the code which will be executed exactly after onInit using Getx
}
}

Related

Keep scroll controller open with Get.offNamed

i'm using Getx as state management
class ProductsController extends GetxController with StateMixin<Posts> {
ScrollController scrollController = ScrollController();
#override
void onInit() {
_getData();
scrollController = ScrollController()..addListener(_loadMore);
super.onInit();
}
_getData() async {}
_loadMore() async {}
#override
void onClose() {
scrollController.removeListener(_loadMore);
super.onClose();
}
}
and everything works perfectly, but for some reasons i need to navigate to same page as replacement by
Get.offNamed(Routes.products, prevent Duplicates: false);
but i note that this void
#override
void onClose() {
scrollController.removeListener(_loadMore);
super.onClose();
}
called and i lost the scroll in the bage ...
so how to keep scrollController open or how to initialize it again when navigate to the same page as replacement
or am i need to use another method to navigate to same page as replacement to it ??
thanks

Flutter GetX call fetch data only once in the build methode

I have a method called getData() which used to load data from API,
and i am displaying data in a separate screen, I have one issue which whenever I navigate to this page it rebuild the whole screen and call the API again and again.
PS: I'm using getX Obx to control the UI
Question: how to call the function only when new data has added
class CategoryPageBinding extends Bindings {
#override
void dependencies() {
Get.put(CategoryPageController(), permanent: true);
}
}
class CategoryPageController extends GetxController {
#override
void onInit() {
super.onInit();
getAllCategories();
}
}
You can call the method in Controller using getX.
#override
void onInit() {
super.onInit();
getData();
}

Should codes be written before super.initState(); or after in Flutter?

Should the code that is being written to initState() function be written before super.initState(); or after?
Which one is proper:
#override
// code here
super.initState();
}
or
#override
super.initState();
// code here
}
both will work.
But if you see from any dependencies or official docs flutter, write your code in initSate() after super.initState();
#overrride
initState(){
super.initState()
//your code
}
reference to this initState
the opposite for dispose(), write your code before super.dispose();
#overrride
dispose(){
//your code
super.dispose()
}
reference to dispose
When I see #Kahoo answer, I check it by cmd + click at super.dispose and super.initstate, I found this for dispose
/// If you override this, make sure to end your method with a call to
/// super.dispose().
///
/// See also:
///
/// * [deactivate], which is called prior to [dispose].
#protected
#mustCallSuper
void dispose() {
assert(_debugLifecycleState == _StateLifecycle.ready);
assert(() {
_debugLifecycleState = _StateLifecycle.defunct;
return true;
}());
}
abstract class State :
/// If you override this, make sure your method starts with a call to
/// super.initState().
#protected
#mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
Both will work fine, but the better practise is to write before super.initState(), because it will do all the initialisations before creating the state widget which will help you in maintaining the check on the Widget State.
But this does not means that the second method will not keep close eye on maintaining the state, But as of better practise the First way is preferred.

difference between running a method before super.initState() and after super.initState()

what is the difference between running a method before super.initState() and after super.initState()
#override
void initState() {
super.initState();
getCurrentUser();
}
#override
void initState() {
getCurrentUser();
super.initState();
}
Explanation for framework: Dart is class based object oriented programming language, so when you build a widget you extend it from a base class StatelessWidget or StatefulWidget. initState is lifecycle method in flutter widget (as you might know) which is only available to override in StatefulWidgets and it called only once. So, it call initState of base class which is StatefulWidget thats why you call super.initState()which in turn creates BuildContext and attached State.
Now your question: I didn't find anything different in calling a method before or after super.initState(). Event I tried adding addPostFrameCallback before super.initState() and it worked fine.
Even super.mounted is also true in both cases.
Suggestion
Dart/Flutter documentation "suggests" to call super.initState() as first method before your body implementation.
But if we look at how it is implemented Documentation
#protected
#mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
it's possible to see that it contains only an assert(). the assert built-in function it's called only in DEBUG mode, not in production mode. So, at the end of the day, it really doesn't matter, because the super.initState() would practically do nothing.

Unhandled Exception: inheritFromWidgetOfExactType(_LocalizationsScope) or inheritFromElement() was called before _ScreenState.initState() completed

I am calling initial method to load data from API using initState. But it is resulting me an error. Here is error:
Unhandled Exception: inheritFromWidgetOfExactType(_LocalizationsScope) or inheritFromElement() was called before _ScreenState.initState() completed.
When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.
My code is:
#override
void initState() {
super.initState();
this._getCategories();
}
void _getCategories() async {
AppRoutes.showLoader(context);
Map<String, dynamic> data = await apiPostCall(
apiName: API.addUser,
context: context,
parameterData: null,
showAlert: false,
);
if(data.isNotEmpty){
AppRoutes.dismissLoader(context);
print(data);
}else {
AppRoutes.dismissLoader(context);
}
}
You need to call _getCategories after initState has completed.
#override
void initState() {
super.initState();
Future.delayed(Duration.zero, () {
this._getCategories();
});
// Could do this in one line: Future.delayed(Duration.zero, this._getCategories);
}
Also, you could do this on a different way, using addPostFrameCallback.
To make this task easier, you could create a mixin to be added to StatefulWidgets.
mixin PostFrameMixin<T extends StatefulWidget> on State<T> {
void postFrame(void Function() callback) =>
WidgetsBinding.instance?.addPostFrameCallback(
(_) {
// Execute callback if page is mounted
if (mounted) callback();
},
);
}
Then, you just need to plug this mixin to you page, like that:
class _MyPageState extends State<MyPage> with PostFrameMixin {
#override
void initState() {
super.initState();
postFrame(_getCategories);
}
}
Use the didChangeDependencies method which gets called after initState.
For your example:
#override
void initState() {
super.initState();
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
this._getCategories();
}
void _getCategories() async {
// Omitted for brevity
// ...
}
Adding a frame callback might be better than using Future.delayed with a zero duration - it's more explicit and clear as to what is happening, and this kind of situation is what frame callback was designed for:
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
_getCategories();
});
}
an alternative is to put it inside PostFrameCallback which is between initState and Build.
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) => getData());
super.initState();
}
getData() async {
}
There are many ways to solve this problem, override initState method:
#override
void initState() {
super.initState();
// Use any of the below code here.
}
Using SchedulerBinding mixin:
SchedulerBinding.instance!.addPostFrameCallback((_) {
// Call your function
});
Using Future class:
Future(() {
// Call your function
});
Using Timer class:
Timer(() {
// Call your function
});
The best solution i think is use the context from the Widget build. And paste the method _getCategories(context) after the build with the context from the tree.
So there is no problem with the widget tree.