I wonder why does setState works after Navigator.push? Actually, I met such examples, but how does it work, should not the Navigator.pushNamed redirect right when it called?
if (user != null) {
Navigator.pushNamed(context, "/chat");
}
// will the setState be executed?
setState(() {
showSpinner = false;
});
Related
I have a page on which I display data via BloC. I added the isLoading variable to display the loading indicator, which is true after two seconds, this value changes to false and the loading indicator disappears and the data is displayed. But I got an error because I use setState(). Tell me how to fix this error?
Widget _child(Size size, BuildContext context, double topPadding) {
return BlocBuilder<MycarsCubit, MycarsState>(
builder: (context, stateElectricvehicles) {
final ElectricvehiclesCubit cubit =
BlocProvider.of<ElectricvehiclesCubit>(context);
if (stateElectricvehicles is MycarsInitial) {
carNumber.text = stateElectricvehicles.number;
carNumber.selection = TextSelection.fromPosition(
TextPosition(offset: carNumber.text.length),
);
if (stateElectricvehicles.id == 0) {
savedCarId = stateElectricvehicles.id;
}
Future.delayed(const Duration(seconds: 2), () {
setState(() {
isLoading = false;
});
});
final SharedPrefs prefs = SharedPrefs();
return FutureBuilder<int?>(
Always add a check mounted (available in StatefulWidget) before calling setState in async function.
Future.delayed(const Duration(seconds: 2), () {
if(mounted) {
setState(() {
isLoading = false;
});
}
});
See if this solves it:
Future.delayed(const Duration(seconds: 2), () {
// Wrap setState in an if:
if (mounted) {
setState(() {
isLoading = false;
});
}
});
This should make sure setState() is not called unless the context is still mounted.
In later versions of flutter lints, you will get a warning about this, saying something like "Do not use context over async gaps!". Meaning if you have an async delay, i.e. an "await", you have to check afterwards if the context is still alive before you use it. 🙂
On Safari for some of my onTap functions, my code is being executed twice. It doesn't always happen just from times to times.
for example:
goToSearchPage() {
Navigator.pushNamed(
context, '/searchPage',
arguments: SearchPageArguments(
matchcode: _controllerSearchInput.text.trim().toString()
)
);
_controllerSearchInput.text = '';
}
onTap: () {
_controllerSearchInput.text = matchcode;
goToSearchPage();
},
When onTap sometimes it loads 2 times searchpage, first time with a correct argument and second time with an empty argument.
An other example:
onTap: () {
setState(() {
_loading = true;
});
http.Client()
.get("https://myApi")
.then((response) =>response.body)
.then(json.decode)
.then((json) {
setState(() {
_loading = false;
});
Navigator.popAndPushNamed(
context, '/paymentPage',
arguments: PaymentPageArguments(
ordersToPay: json
)
);
});
}
In this case after my API is being called paymentPage is not showing because I think navigator is being pop twice instead of one time. My API is only being call one time though.
Those weird behaviors only happens in safari, I'm not sure how i could debug it.
Im creating an app thats making reservations for boat rentals, but i struggle to fix this problem any1 can help?
Providing code samples:
if (docs.size == 0) {
reservations.doc(resID).set({
'resID': resID,
'name': name,
"surname": surname,
"phoneNumber": phoneNumber,
"rental": ProductCardInCart.rental,
'boat': ProductCardInCart.boat,
'date': date,
'time': time
}).then((value) {
print("Reservation made");
setState(() {
Body.empty = true;
});
}).catchError((error) => print("Failed to reservate: $error"));
} else if (docs.size != 0) {
setState(() {
Body.empty = false;
});
print('jestjus');
}
});
} else {
return;
}
});
}
}
this setstate is working well
.then((value) {
print("Reservation made");
setState(() {
Body.empty = true;
});
but this one isnt and its throwing exception
} else if (docs.size != 0) {
setState(() {
Body.empty = false;
});
print('jestjus');
}
Error that its throwing:
7980): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: setState() called in constructor: ReservationMakingState#861c9(lifecycle state: created, no widget, not mounted)
E/flutter ( 7980): This happens when you call setState() on a State object for a widget that hasn't been inserted into the widget tree yet. It is not necessary to call setState() in the constructor, since the state is already assumed to be dirty when it is initially created.
Thanks for help in advance
The reason that your setState isn't working is because your widget is still being built. It can't update until AFTER the widget has completed its first build.
the reason that this one works
.then((value) {
print("Reservation made");
setState(() {
Body.empty = true;
});
});
is because it is happening after a future .then(() {});
if you would like to have your widget rebuild after it has initially been set up you can useBe careful using this. if you use it within your build method, you will get stuck in a loop! You should have this in a initState method or have some conditional statement before this is run
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
//do something call your set state here
});
}
I have a problem implementing a login button, when I press it, it will not function at first, but when I press it again (same value fields) it works.
here's my code
Button:
Center(child: RaisedButton(onPressed: (){
setState(() {
onPressedLogin(userName.text,password.text);
});
}
The OnPressedLogin():
void onPressedLogin(String userName,String password) async{
bool isValid = false;
var value = await dataBaseHelper.getUserList();
for(User userOB in value){
//print(userOB.password+" "+password),
if(userName == userOB.username && password == userOB.password) {
isValid = true;
this.password.clear();
this.userName.clear();
inputTextColor = Colors.grey[850];
invalidCredentials = "";
print("YES");
//Navigator.push(context, MaterialPageRoute(builder: (context) => Home()));
break;
}
}
if(!isValid){
inputTextColor = Colors.red[800];
invalidCredentials = "Invalid Credentials";
}
You are using a Future but in setState() you are not waiting for it so that's way it work in the second press (the value take time to change).
To make it work with single press you have to a wait the Future to complete before rebuilding, here how:
First change the return type of the function
Future<void> onPressedLogin(String userName,String password)
Then in the RaisedButton
onPressed: () async {
await onPressedLogin(userName.text,password.text);
setState(() {});
},
The moment you setState(), the UI will refresh!
Probably that's the issue, let me explain:
What you should do is to call your function before setState(), so that the screen is refreshed with the new info.
Center(child: RaisedButton(onPressed: (){
onPressedLogin(userName.text,password.text);
setState(() {
//Variables that change for the refresh.
});
}
In your specific case, I don't see the need for SetState() as you are only printing values in log, not changing the UI.
Hope it is helpful.
I have a simple DropdownButton element and onChange event.
onChanged: (String newValue) {
if (newValue == "Log out") {
print("Inside IF");
setState(){
user.navigateToPreviousPage(Login(), context, false);
}
}
},
But from here I only get this print("Inside IF")... It does not call function which should remove user's token and navigate to login page.
In addition, there are no errors or warnings...
What is wrong here? My whole class is Stateless Widget. Should I change it to Stateful?
You are calling setState in a wrong way:
setState(){
user.navigateToPreviousPage(Login(), context, false);
}
Correct way:
setState(() {
user.navigateToPreviousPage(Login(), context, false);
});
And you should call Navigator.pop from the widget you want to dismiss :)