I just started learning Flutter and as a beginner I'm facing some issues about understanding a state. I watched some videos on YouTube, read articles online. They explain the reason why one should use a Stateful Widget instead of Stateless. But I can't really understand what part of an app needs to be a Stateful Widget and what the use of the setState method is. Also what's the difference between the state of a widget and state of the app?
Flutter is declarative. This means that Flutter builds its user interface to reflect the current state of your app:
State can be described as "whatever data you need in order to rebuild your UI at any moment in time".
When the state of your app changes (for example, the user flips a switch in the settings screen), you change the state, and that triggers a redraw of the user interface.
There is no imperative changing of the UI itself (like widget.setText)—you change the state, and the UI rebuilds from scratch.
The state that you do manage yourself can be separated into two conceptual types: ephemeral(widget state on your question) state and app state.
Ephemeral state
Ephemeral state (sometimes called UI state or local state) is the state you can neatly contain in a single widget.
There is no need to use state management techniques (ScopedModel, Redux, Provider, bloc, etc.) on this kind of state. All you need is a StatefulWidget.
You only need to use setState to alter your current state.
For example, below, you see how the currently selected item in a bottom navigation bar is held in the _index field of the _MyHomepageState class.
In this example, _index is ephemeral state.
class MyHomepage extends StatefulWidget {
const MyHomepage({Key? key}) : super(key: key);
#override
_MyHomepageState createState() => _MyHomepageState();
}
class _MyHomepageState extends State<MyHomepage> {
int _index = 0;
#override
Widget build(BuildContext context) {
return BottomNavigationBar(
currentIndex: _index,
onTap: (newIndex) {
setState(() {
_index = newIndex;
});
},
// ... items ...
);
}
}
Here, using setState() and a field inside the StatefulWidget’s State class is completely natural. No other part of your app needs to access _index.
The variable only changes inside the MyHomepage widget. And, if the user closes and restarts the app, you don’t mind that _index resets to zero.
App state
State that is not ephemeral, that you want to share across many parts of your app, and that you want to keep between user sessions, is what we call application state (sometimes also called shared state).
Examples of application state:
User preferences
Login info
Notifications in a social networking app
The shopping cart in an e-commerce app
Read/unread state of articles in a news app
For managing app state, you’ll want to research your options. Your choice depends on the complexity and nature of your app, your team’s previous experience, and many other aspects.
Here's a link to an example on app wide state management using provider(one of many state management libraries), Example.
Here's a list of libraries that are used for app wide state management, Options.
In summary, there are two conceptual types of state in any Flutter app. Ephemeral state can be implemented using State and setState(), and is often local to a single widget. The rest is your app state.
Both types have their place in any Flutter app, and the split between the two depends on your own preference and the complexity of the app.
In the Stateless widget, the build function is called only once which makes the UI of the screen. It means through that widget you cannot change the UI again. It will render(build) the UI at once. So for those widgets, you need to send the information before building the widget.
Stateful Widgets: The widgets whose state can be altered once they are built are called stateful Widgets. This simply means the state of an app can change multiple times with different sets of variables, inputs, data. Below is the basic structure of a stateful widget. That means you can change the UI of this widget without building it again with help of the setState method.
For more information refer - https://medium.com/flutter-community/flutter-stateful-vs-stateless-db325309deae
if we want to make changes in our UI so that we use statefulWidget
otherwise we use statelessWidget.
in most case we will be using statefulWidget.
that's it.
Related
I looked at Riverpod's counter example and noticed it uses ConsumerWidget instead of ConsumerStatefulWidget.
If ConsumerWidget can show state changes, is there any need to use ConsumerStatefulWidget? Why Riverpod, as a state management solution, has both stateful and stateless consumer widgets? It seems there is something I haven't yet comprehend
ConsumerStatefulWidget is here for if you want local state in your widget. Like instantiating an AnimationController
Typically providers are for shared state. But they don't deal with local state.
Hence why you still sometimes need Statefulwidgets (or flutter_hooks if that's your thing)
I'll also add that we can quickly enough replace StatefulWidget with ConsumerStatefulWidget (and State with ConsumerState) to access the ref variable throughout the widget. This is very useful when we have a previously written complex StatefulWidget widget with lots of controllers (well, just imagine!) and suddenly we need to access ref and use Riverpod to its full potential.
Then it becomes obvious and looks amazing!
Afterword: later on you will also find out that ConsumerWidget is actually a ConsumerStatefulWidget :)
In one of my projects, I am using flutter_bloc package.
In that example, I instantiated bloc inside didChangeDependencies(). So bloc lives during the lifecycle of a screen.
However, my colleague told me not to initialize there. He said bloc should be initialized in app.dart where It can live over the lifecycle of the app. Because, in cases where there should be multiple screens on tablet, it will break the code.
For example, I have ScreenA, ScreenB and ScreenC. you can go to ScreenB and ScreenC through ScreenA. ScreenB and ScreenC use the same bloc, and bloc is initialized sepearately in each screens. He is saying that if the requirement is to show ScreenB and ScreenC simultaneously on a tablet, it might break the code. How?
Could you suggest me what is best? Or does it depend on the usecase?
It is the best practice to initiate bloc instance during initState as it runs only once per widget lifecycle. didChangeDependencies() may be called multiple times for example if widget is moved in the widget tree or widget gets notified of InheritedWidget change, so bloc will get new instance like that and you dont want that. What your collegue is talking is more about BlocProviders scope and sure is normal practice, but for some small-usecase-bloc might be redundant. That is up to you to decide does your whole app needs to be in scope of this bloc. Keep in mind that if lazy property is not set to false, your bloc will be created with the first call to it.
I get the general idea that the StatefulWidget my get rebuild very often, and even get assigned to a different State if not using key in some cases. However the State of that widget always exists in memory. I need to change some data of the State when it's not shown. Is it safe to keep the reference of that State instance for example in a singleton and change its data?
Specifically, I have a StatefulWidget(call it homapage) with PageView. Its State keeps the reference of the PageController. I want to change the controller.page when the screen is showing other tabs rather than homepage. I did this via keeping a reference of the State in a singleton. In order to do it, I need to make the State class public by deleting the _ in front of the State class name. If feels unsafe and against the Flutter design philosophy to me.
The state will be destroyed when a widget that uses that state is no longer in the widget tree. We recommend that you use GlobalKey and don't use a singleton as a reference to the State. Using InheritedWidget is also a good option.
I am developing a mobile application using Flutter. I am new to Flutter. I am using BLoC for state management. I know that it is specially designed for management async execution. But also the purpose of BLoC is for state management. But I am a little bit confused and not quite sure how to handle the primary data types in BLoC.
Let's imaging the I have a button and an image. The functionality would be that when the button is clicked, the visibility of the image will be toggled. Literally, we just need to use a boolean variable to manage the state of the image. This is how I would implement it.
I have a bloc class called HomeBloc with the following implementation.
class HomeBloc {
bool _isImageDisplayed = true;
bool get isImageDisplayed => _isImageDisplayed;
void set isImageDisplayed(bool displayed) {
this._isImageDisplayed = displayed;
}
//the rest of the code for other functionalities goes here
}
final homeBloc = HomeBloc();
Then in the HomePage widget, I update the state of the image like this inside the setState method when the button is clicked.
this.setState(() {
homeBloc.isImageDisplayed = false;
});
My question is that "is it the standard way to manage primary data type in the BLoC in Flutter"? Is this the best practice? Do we need to use StreamBuilder? Do we even need to manage it inside the BLoC?
It's not the best practice I guess, as using setState becomes really hard on big applications and re-rendering widgets that don't change for no reason. Imagine making an e-commerce app and you just go to the product page, you add the product you like into the cart, but you have designed in your home page a cart icon with a red dot with a number inside it to specify how much products you got in your cart, so you handle the state of that icon in the main.dart file by passing a function that setState the home page route or maybe the whole application, it's hard, isn't it?.
Thankfully, BLoC and Provider patterns are basically using setState but in a better way so you don't have to re-render the whole page just for a small change in a text or something else, but you just re-render a specific widget in your widget tree.
I also recommend using BLoC Provider which is built on Provider and RxDart (Streams) as it makes great isolation between UI code and business code.
Check Provider and BLoC Provider.
I'm just learning flutter - I build a few basic tutorials and am now trying to build a simple notepad application.
https://github.com/sketchbuch/examples_flutter/blob/master/notes/lib/src/components/notepad/notepad.dart
In this file I have a stateful widget which has a state property. What I don't understand is why I need the stateful widget at all... the state class seems to be doing everything including building the list of notes.
Am I doing this right? It doesn't seem right that state builds the whole stateful widget...maybe it is just because my app is basic at the moment but the stateful widget doesn't seem to do anything at the moment.
I just would have thought that the staefulwidget would handle rendering and state would just be an object storing properties
As pointless as an empty StatefulWidget subclass looks like, it is necessary. That class is what allows Flutter to manipulate the State subclass.
Without a StatefulWidget, Flutter is unable to create/update/dispose of a State.
StatefulWidget subclass is also a way to customize the behavior of State by adding fields in StatefulWidget and using them in the State class.
You're saying
My Notepad widget as such is not doing anything but my _NotepadState is. Then why should I use the redundant Notepad widget?
Why is it required?
Your Notepad widget is not alone. It has super classes. It extends StatefulWidget which in turn extends Widget (which extends DiagnosticableTree which extends Diagnosticable).
The super classes are doing all the heavy lifting for you and that you had to write almost zero code. Mostly it is used to accept parameters and create state.
Hope that helps!