flutter setstate from another function? - flutter

I have a void function called updateCardCode() which takes newCardCode as argument,
in the same class, I have a second function called showPopUp() which is an async function and returns showDialog function returns AlertDialog, also in the same class I have a build widget.
here is updateCardCode() code:
void updateCardCode(String newCardCode) {
setState(() {
cardCode1 = newCardCode;
});
}
showPopUp() calls updateCardCode() if certain conditions are met but I want setState to have a result on the Build widget which returns Scaffold. is that possible?

call the setState at the end of the showPopUp() function like
showPopUp().then(()=>setState((){}));

Related

Anonymous function and its parameter in Dart Flutter

I'm very new to Dart. I was learning basic stuff for Flutter. And I've got some questions while working on BottomNavigationBar:
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
I have no idea why there's index as a parameter in the function. Where is it coming from?
Also, in the setState function, why is there a function and what does it mean?
I'm sorry these questions are very elementary but I couldn't find clear answers!
Thank you in advance!
onTap: (index) {} : Index use for Keep track of the index of the selected BottomNavigationBarItem.
setState() : Whenever you change the state of a State object, make the change in a function that you pass to setState.
For more info :
onTap : https://api.flutter.dev/flutter/material/BottomNavigationBar/onTap.html
setState : https://api.flutter.dev/flutter/widgets/State/setState.html
Firstly onTap is a callback function and depending on widget it can have zero o more parameters. For example in InkWell widget the onTap callback has no parameters and in BottomNavigationBar the onTap callback take index as parameter to recognize the index of items in that widget.
Secondly, as you know setState function is used for updating UI and called inside State class.
When you use StatefulWidget, every StatfulWidget has a state object like code below:
class MyWidget extends StatefulWidget { // immutable Widget
#override
_MyWidgetState createState() => _MyWidgetState();
// creating State Object of MyWidget
}
class _MyWidgetState extends State<MyWidget> { // State Object
#override
Widget build(BuildContext context) {
return Container();
}
}
Since StatefulWidget itself is immutable (cannot be modified), we use State Object to modify the UI.
We tell this State Object to update our screen's UI using a function called setState().
void setState(VoidCallback fn) {
...
}
This setState() takes a function as it's parameter.
The function called inside setState does not need have any parameter as well.
finally, you can hold ctrl key and click on which function you want and see the implementation of the function.

How to force initState every time the page is rendered in flutter?

I am adding some data into the SharedPreferenceson page2 of my app and I am trying to retrieve the data on the homepage. I have used an init function on page 1 as follows:
#override
void initState() {
super.initState();
_getrecent();
}
void _getrecent() async {
final prefs = await SharedPreferences.getInstance();
// prefs.clear();
String b = prefs.getString("recent").toString();
Map<String, dynamic> p = json.decode(b);
if (b.isNotEmpty) {
print("Shared pref:" + b);
setState(() {
c = Drug.fromJson(p);
});
cond = true;
} else {
print("none in shared prefs");
cond = false;
}
}
Since the initState() loads only once, I was wondering if there was a way to load it every time page1 is rendered. Or perhaps there is a better way to do this. I am new to flutter so I don't have a lot of idea in State Management.
you can override didChangeDependencies method. Called when a dependency of the [State] object changes as you use the setState,
#override
void didChangeDependencies() {
// your codes
}
Also, you should know that using setState updates the whole widget, which has an overhead. To avoid that you should const, declaring a widget const will only render once so it's efficient.
First thing is you can't force initState to rebuild your widget.
For that you have setState to rebuild your widget. As far as I can
understand you want to recall initState just to call _getrecent()
again.
Here's what you should ideally do :
A simple solution would be to use FutureBuilder. You just need to use _getrecent() in FutureBuilder as parent where you want to use the data you get from _getrecent(). This way everytime your Widget rebuilds it will call _getrecent().
You simply use setState() methode if you want to update widget. Here's documentation for this https://api.flutter.dev/flutter/widgets/State/setState.html
init function will render it only once initially, to avoid that -
You can use setState( ) method to re-render your whole widget.

Need explanation for setState() function in Flutter

I am confused on why do we have to put a function in setState to update variables. I could instead update the variables and call setState. I modified the code from https://flutter.dev/docs/development/ui/widgets-intro
class _CounterState extends State<Counter> {
int _counter = 0;
void _increment() {
setState(() {
_counter++;
});
}
Instead, I thought of doing this
class _CounterState extends State<Counter> {
int _counter = 0;
void _increment() {
_counter++;
setState(() {
});
}
This still works, now I was thinking why make setState() have a function as a parameter, instead setState could not have any parameters like setState(); and we would just call it after we update our variables.
You'll find the answer in the official docs:
The provided callback is immediately called synchronously. [...] If you just change the state directly without calling setState, the framework might not schedule a build and the user interface for this subtree might not be updated to reflect the new state.
I think the problem is that UI and state object will not be in sync for a short period of time if you call setState((){}); after changing the state.
it can not run properly in the big project. So answer of your problem is like this, if you dont use setState(() => {});, your screen can not render if you change any value of variable. So if you want to effect when you change value of variable in the screen, you have to use setState(() => {});.

Pass callback Function as Parameter to Widget while keeping Lint Rules "argument_type_not_assignable"

In my widget I pass a function callback as a parameter to the widget:
onTap: onTapRestaurantItemCallback
Out in the screen widget, which contains the widget above, I then execute the function callback:
onTapRestaurantItemCallback: () { // Handling the callback method }
I am using Lint for Dart/Flutter to check my code:
https://pub.dev/packages/lint
The linter is not happy with my function parameter and gives me an error, I am violating the rule:
argument_type_not_assignable
"The argument type 'Function' can't be assigned to the parameter type 'void Function()'"
https://dart.dev/tools/diagnostic-messages#argument_type_not_assignable
Apparently the problem is that the widgets "onTap" expects void, whereas the callback returns a Future.
I can make the error go away in the widget by writing:
onTap: () => onTapRestaurantItemCallback
But then my function callbacks stop working.
Do you know how I can pass a function callback to my widget like I do and still keep the
argument_type_not_assignable
lint rule?
Below I paste a more full code on the scenario I have described above:
// WIDGET USED BY OTHER WIDGET BELOW
class RestaurantItem extends StatelessWidget {
// FUNCTION CALLBACK
final Function onTapRestaurantItemCallback;
const RestaurantItem({
// FUNCTION CALLBACK
#required this.onTapRestaurantItemCallback,
});
#override
Widget build(BuildContext context) {
return GestureDetector(
// FUNCTION CALLBACK
onTap: onTapRestaurantItemCallback,
// CONTAINING SCREEN WIDGET - USING WIDGET ABOVE
// .... //
RestaurantItem(
// FUNCTION CALLBACK
onTapRestaurantItemCallback: () => { // Handling the callback method }
),

Does setState() trigger itself when variables and data change just like stream and streambuilder does?

class _LocationScreenState extends State<LocationScreen> {
WeatherModel weather = WeatherModel();
String weatherMessage;
String weatherIcon;
String cityName;
int temperature;
#override
void initState() {
super.initState();
updateUI(widget.locationWeather);
}
void updateUI(dynamic weatherData) {
setState(() {
temperature=weatherData['main']['temp'].toInt();
var condition = weatherData['weather'][0]['id'];
cityName=weatherData['name'];
weatherIcon=weather.getWeatherIcon(condition);
weatherMessage=weather.getMessage(temperature);
});
}
Hi I am getting confused with what setState() does. If the value of temperature or condition or anything changes inside that of setState does setState() trigger itself to update the UI and build UI with updated temp or condition or do I have to invoke updateUI function myself to invoke setState and update the UI?
SetState Rebuild the build method whenever it called.
SetState never call it self, you have to call it. If you change value of your variable and did not use SetState then it will not reflect in UI, to do so you have to call SetState.
As you put you code in updateUI in SetState, so it will update ui whenever you call that method, where as if you don't use SetState there then it will not reflect changes in UI.
documentation states that setState(fn()), Calling setState notifies the framework that the internal state of this object has changed in a way that might impact the user interface in this subtree, which causes the framework to schedule a build for this State object.
whenever a setState called the ui will be scheduled for a build based on the new state.
Eg:
class _MyWidgetState extends State<MyWidget> {
String text;
#override
void initState() {
super.initState();
text = "Hello";
}
void updateUI(String action) {
setState(() {
text = action;
});
}
#override
Widget build(BuildContext context) {
return Column(children: [
Text(text, style: Theme.of(context).textTheme.headline4),
MaterialButton(
onPressed: () {
updateUI("Pressed");
},
child: Text("Change state"))
]);
}
}
Note : initState() will be called once in the life cycle of Stateful widget.
setState():
Notify the framework that the internal state of this object has changed.
Whenever you change the internal state of a State object, make the change in a function that you pass to setState:
setState(() { _myState = newValue; });
Calling setState notifies the framework that the internal state of this object has changed in a way that might impact the user interface in this subtree, which causes the framework to schedule a build for this State object.
Nope, you need to call it in order to "re-draw" the current stateful widget. I believe the variable that changed doesn't need to be wrapped inside the setState either, as long as it's changed before the setState.