Understanding Stateful and Stateless Widgets in Flutter¶
Overview¶
In Flutter, everything is a widget. Widgets are the building blocks of a Flutter app's user interface. They can be broadly categorized into two types: Stateful and Stateless.
Stateless Widgets¶
A Stateless widget is immutable, meaning its properties cannot change—once created, it cannot be altered. Stateless widgets are typically used for static content.
Stateful Widgets¶
A Stateful widget is dynamic and can change during the app's lifecycle. It can update its state based on user interactions or other factors, and it redraws the widget whenever the state changes.
Real-World Analogies¶
Stateless Widget: A Poster¶
Imagine a poster on a wall. The poster is static; it doesn't change. You can look at it, read it, but it stays the same unless you replace it with a new poster. This is similar to a Stateless widget.
Stateful Widget: A Whiteboard¶
Now, think of a whiteboard. You can write on it, erase it, and rewrite on it multiple times. It changes based on your interactions. This is similar to a Stateful widget.
Examples in Flutter¶
Stateless Widget Example: Static Greeting¶
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Stateless Widget Example')),
body: Center(child: GreetingWidget()),
),
);
}
}
class GreetingWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text('Hello, World!');
}
}
In the example above:¶
GreetingWidget
is a Stateless widget that displays a static text "Hello, World!"
Stateful Widget Example: Interactive Counter¶
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Stateful Widget Example')),
body: Center(child: CounterWidget()),
),
);
}
}
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Counter: $_counter'),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('Increment'),
),
],
);
}
}
In the example above:¶
CounterWidget
is a Stateful widget that displays a counter and a button_CounterWidgetState
holds the state for the widget, including the_counter
variable- When the button is pressed,
_incrementCounter
is called, which updates the state and causes the widget to redraw with the new counter value
Key Differences¶
Stateless Widget¶
- Immutable: Properties cannot change once the widget is built
- Use Cases: Static content like text, icons, and images
- Lifecycle: Build method is called once
Stateful Widget¶
- Mutable: Properties can change over time based on user interactions or other events
- Use Cases: Interactive content like forms, animations, and any content that can change
- Lifecycle: Build method can be called multiple times as the state changes
Practical Applications¶
Stateless Widget Use Case: Displaying User Profile¶
A profile page that displays static information like the user's name and profile picture.