Widgets are the basic building blocks of the app's user interface in Flutter development. They encapsulate important aspects like layout and interface elements, allowing developers to create responsive and attractive designs. Two primary types of Widgets that lay the foundation of any Flutter application include Stateful and Stateless widgets in Flutter.
In Flutter, everything is a widget! Widgets are, quite literally, the heart and soul of Flutter. They describe how part of the UI should look based on a given configuration and state, and they can also include other widgets, forming a widget tree. Whether it is the entire app or an individual button, everything on the screen is a widget.
Widget in the Flutter app
Flutter Stateful and Stateless widgets are two fundamental kinds of widgets that Flutter provides. As their names imply, Stateless Widgets are static and don't hold mutable state, while Stateful Widgets are dynamic, and they maintain a mutable state that can change over time.
Throughout this blog, we will unveil the lifecycle and operational intricacies of these central component types: The Stateless and Stateful widget in Flutter that empower developers to craft interactive and flexible user experiences.
Before further dissecting these widget types, if you haven't already, it's a good idea to familiarize yourself with an excellent IDE plugin, WiseGPT. WiseGPT provides real value to your development workflow in many ways. For instance, code creation could become daunting when dealing with complex widget structures. WiseGPT generates code for you, mirroring your coding style and making your life a lot easier. We will discuss it more later in this blog post.
Flutter Stateless widgets are those components that describe a part of the user interface which can be determined only by configurations in the constructor. They don't store mutable states. Examples of Stateless widgets are Icon, IconButton, and Text.
Here is how you define a simple Stateless widget in Flutter:
1 class MyStatelessWidget extends StatelessWidget { 2 // This widget is the root of your application. 3 @override 4 Widget build(BuildContext context) { 5 return Container( 6 child: Text('This is a Stateless Widget'), 7 ); 8 } 9 } 10
In the code snippet above, MyStatelessWidget extends StatelessWidget and overrides the build method. The build method describes the user interface part represented by this widget.
Flutter Stateless widgets go through a simple lifecycle that is composed of only one stage: Creation.
Lifecycle of Stateless widget
As we've seen, a stateless widget is easy to instantiate. You create an instance of it and Flutter takes care of the rest. It will render the widget and then destroy it.
Render is the next phase once the widget is created. In this phase, the Flutter framework visits the build method, which returns a new tree of widgets, which is further used for rendering.
Here is the code:
1 @override 2 Widget build(BuildContext context) { 3 return Container( 4 child: Text('This is a Stateless Widget'), 5 ); 6 } 7
Once rendered, the Stateless widget waits for the next build command. Whenever the parent widget decides that it needs to change the configuration of this widget, it will dispose of it and replace it with a new widget.
This covers the basics of Stateless widgets and their life cycle in Flutter. You can better manage your application's UI and architecture by understanding these fundamental concepts.
Stateful widgets in Flutter are those that can change their state over time. The changes could be in user interactions or real-time data updates. Stateful widgets include checkboxes, radio buttons, sliders, form inputs, etc.
Let's define a creative example of a stateful widget. We will make a widget that toggles the visibility of a text when you click on a button:
1 class MyStatefulWidget extends StatefulWidget { 2 MyStatefulWidget({Key? key}) : super(key: key); 3 4 @override 5 _MyStatefulWidgetState createState() => _MyStatefulWidgetState(); 6 } 7 8 class _MyStatefulWidgetState extends State<MyStatefulWidget> { 9 bool _showText = true; 10 11 void _toggleText() { 12 setState(() { 13 _showText = !_showText; 14 }); 15 } 16 17 @override 18 Widget build(BuildContext context) { 19 return Container( 20 child: Column( 21 children: <Widget>[ 22 if (_showText) 23 Text('Now you see me!'), 24 ElevatedButton( 25 onPressed: _toggleText, 26 child: Text('Toggle Text'), 27 ), 28 ], 29 ), 30 ); 31 } 32 } 33 34
In the code snippet above, we first create a StatefulWidget named MyStatefulWidget. We then define a _MyStatefulWidgetState class where we manage the state of the visibility of the text. By tapping the button, we can toggle the visibility of the text.
Maintaining and managing the state is crucial for any application, and this is where Stateful Widgets show their true potential.
The term 'State' in Flutter refers to the data that can be read synchronously when the build method is called and might change during the lifetime of a widget. In other words, a widget can change due to user interactions or if an internal event triggers a change in the data.
Contrary to Stateless Widgets, Stateful Widgets have a more complicated life cycle. It includes the stages of Initialization, State Creation, Rendering, and Disposal.
Lifecycle of Stateful widget
The lifecycle of a Stateful Widget in Flutter starts with the constructor call. The Flutter framework calls the createState() method, which creates a default configuration for the new Stateful Widget. The code snippet below shows this:
1 class MyStatefulWidget extends StatefulWidget { 2 MyStatefulWidget({Key? key}) : super(key: key); 3 4 @override 5 _MyStatefulWidgetState createState() => _MyStatefulWidgetState(); 6 } 7
The createState() method is overridden and returns a new instance of the state class, _MyStatefulWidgetState.
This is where the build() function comes into play. It takes the context of the current state and builds context to create the widget and its sub-widget.
Here is the rendering part in our initial example:
1 @override 2 Widget build(BuildContext context) { 3 return Container( 4 child: Column( 5 children: <Widget>[ 6 if (_showText) 7 Text('Now you see me!'), 8 ElevatedButton( 9 onPressed: _toggleText, 10 child: Text('Toggle Text'), 11 ), 12 ], 13 ), 14 ); 15 } 16
Whenever a StatefulWidget is removed from the tree, the system invokes the dispose() method. You should perform your cleanup logic in this method, such as cancelling animations, streams, dismissing controllers, and more.
Getting a grip on the Stateful Widgets lifecycle will enhance your Flutter application development skills by providing an optimal way of managing your application's state.
Stateful vs Stateless widget
Though Stateless Widgets are pretty handy and easy to understand, their drawback is that they require a rebuild of the widget tree whenever a change is made, thereby consuming memory and processing time.
On the other hand, Stateful Widgets allow for changes in the state without needing a complete rebuild of the widget tree, thereby providing a more performant solution for dynamic content.
Stateless Widgets are preferable when the part of the interface they represent depends only on its configuration and not on any user interaction, internal timer, or external event. Stateless Widgets are less complex and require less code. Examples include but are not limited to, Text, Icon, and RaisedButton Widgets.
Stateful Widgets are used when change over time is required. This could be a result of user interactions or a change in data from an external source. Examples include CheckBox, Radio, Slider, InkWell, Form, and TextField.
Understanding the differences between Stateless and Stateful Widgets is critical in knowing when to utilise each in your Flutter apps.
As your knowledge of widgets expands, you may find it more convenient to use tools like WiseGPT to generate code when working with complex widget structures efficiently. It saves time and effort, increasing productivity in your development process.
For our practical application, let's create a simple Flutter app. This app will display a list of items where each item can be marked as 'favorite'. This action will demonstrate the use of both Stateless and Stateful widgets.
First, we will create our item as a stateless widget. This widget will consist of Text (which remains unchanged) widget components and an outlined heart icon (a stateless widget that does not change when interacted upon).
Refer to the below code:
1 class Item extends StatelessWidget { 2 final String name; 3 4 Item(this.name); 5 6 @override 7 Widget build(BuildContext context) { 8 return Card( 9 child: ListTile( 10 title: Text(name), 11 trailing: IconButton( 12 icon: Icon(Icons.favorite_border), 13 onPressed: () {}, 14 ), 15 ), 16 ); 17 } 18 } 19
Here, the Item widget takes a name (the item's name), which does not change over time, and displays it on the screen.
Now, we will modify our item to become a Stateful widget. This widget comprises an outline heart icon, which will fill with color when tapped, indicating that the item has been marked as a 'favorite'.
Update the Item widget to become a stateful widget as follows:
1 class Item extends StatefulWidget { 2 final String name; 3 4 Item(this.name); 5 6 @override 7 _ItemState createState() => _ItemState(); 8 } 9 10 class _ItemState extends State<Item> { 11 bool _isFavorite = false; 12 13 void toggleFavorite() { 14 setState(() { 15 _isFavorite = !_isFavorite; 16 }); 17 } 18 19 @override 20 Widget build(BuildContext context) { 21 return Card( 22 child: ListTile( 23 title: Text(widget.name), 24 trailing: IconButton( 25 icon: Icon( 26 _isFavorite ? Icons.favorite : Icons.favorite_border, 27 ), 28 onPressed: toggleFavorite, 29 ), 30 ), 31 ); 32 } 33 } 34
In the ItemState, we define an isFavorite boolean field that states whether the item is 'favorite' or not. The toggleFavorite function changes this field's value and calls setState to update the UI.
Widgets in Flutter are the elemental building blocks that shape how your app looks and functions; understanding them and their lifecycle is crucial to becoming proficient in app development with Flutter.
With the essential knowledge of Stateless and Stateful Widgets and their particular lifecycles under your belt, you've taken a significant step towards crafting interactive, efficient, and user-friendly Flutter apps. A well-timed use of the right widget type can dramatically improve the performance and readability of your code.
That’s where the superpower of WiseGPT can help you with!
To further enhance your Flutter development experience and simplify the process of writing widgets code, I highly recommend using the WiseGPT plugin. WiseGPT is an intelligent IDE plugin designed to assist developers like us in writing code seamlessly and efficiently.
WiseGPT
WiseGPT streamlines the code generation process and seamlessly matches your style, contributing significantly to producing efficient and maintainable code. Especially when dealing with complex widget structures and stateful interactions, WiseGPT empowers you to achieve more while writing less code.
Build powerful apps for Flutter using WiseGPT
As we conclude this exploration into the world of stateful and stateless widgets in Flutter, I encourage you to dive into practical implementation, using these concepts and tools like WiseGPT to master widget management. Who knows, perhaps the next big hit in the app market could be a product of your newfound wisdom.
Thank you for joining us on this deep dive into Flutter Widgets. Remember, creativity is within your grasp, and tools like WiseGPT are deployed to help propel you toward it.
Keep learning, keep implementing, and keep creating
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.