Flutter Stateless Stateful
Understanding the difference between StatelessWidget and StatefulWidget is fundamental to Flutter development.
This section will deeply analyze the usage scenarios and internal mechanisms of these two types of Widgets.
* * *
## Core Differences
There are two main types of Widgets in Flutter, and their fundamental difference lies in whether they can hold mutable state.
| Feature | StatelessWidget | StatefulWidget |
| --- | --- | --- |
| State | Immutable | Mutable |
| Rebuild Timing | Only when parent Widget rebuilds | When state changes + parent Widget rebuilds |
| Performance | Higher (no need to listen for state) | Slightly lower (requires state management) |
| Use Cases | Static content | Dynamic interactive content |
* * *
## StatelessWidget Explained
StatelessWidget is suitable for content that does not change over time. Once created, all its properties are final and cannot be modified.
### Use Cases
* Displaying static text, images, icons
* Showing data lists (data source from parent Widget)
* Layout containers without user interaction
* Read-only display parts in forms
## Example: Complete StatelessWidget Example
import'package:flutter/material.dart';
// User information display component (stateless)
class UserCard extends StatelessWidget {
// Properties defined as final to ensure immutability
final String name;
final String email;
final String avatarUrl;
// const constructor improves performance
const UserCard({
super.key,
required this.name,
required this.email,
this.avatarUrl='',
});
@override
Widget build(BuildContext context){
return Card(
child: Padding(
padding:const EdgeInsets.all(16.0),
child: Row(
children:[
// Avatar
CircleAvatar(
backgroundImage: avatarUrl.isNotEmpty
? NetworkImage(avatarUrl)
:null,
child: avatarUrl.isEmpty
?const Icon(Icons.person)
:null,
),
const SizedBox(width:16),
// User info
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:[
Text(
name,
style:const TextStyle(
fontSize:18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height:4),
Text(
email,
style: TextStyle(
color: Colors.grey,
),
),
],
),
),
],
),
),
);
}
}
* * *
## StatefulWidget Explained
StatefulWidget is suitable for scenarios that require responding to user interactions or data changes. It consists of two parts: the Widget itself (immutable) and a State object (mutable).
### Use Cases
* Dynamic data such as counters, timers
* Form inputs
* Animation control
* Network request status display
* User interaction responses
### State Object Lifecycle
| Method | Description |
| --- | --- |
| initState | Called when Widget is first created, used for initializing state |
| didChangeDependencies | Called when Widget's dependencies change |
| build | Builds UI, called every time state changes |
| didUpdateWidget | Called when parent Widget rebuilds |
| dispose | Called when Widget is removed, used for resource cleanup |
## Example: Complete StatefulWidget Example
import'package:flutter/material.dart';
// Counter application
class CounterApp extends StatefulWidget {
const CounterApp({super.key});
@override
State createState()=> _CounterAppState();
}
class _CounterAppState extends State{
// Counter state
int _counter =0;
// Timer (for demo purposes)
Timer? _timer;
// 1. initState - Initialize state
@override
void initState(){
super.initState();
// Initialize counter
_counter =0;
// Start a timer (increase every second)
_timer = Timer.periodic(const Duration(seconds:1),(timer){
_increment();
});
}
// 2. didChangeDependencies - Called when dependencies change
@override
void didChangeDependencies(){
super.didChangeDependencies();
}
// 3. build - Build UI
@override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title:const Text('Counter'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children:[
const Text(
'Current count:',
style: TextStyle(fontSize:20),
),
Text(
'$_counter',
style:const TextStyle(
fontSize:48,
fontWeight: FontWeight.bold,
),
),
],
),
),
// Increment button
floatingActionButton: FloatingActionButton(
onPressed: _increment,
child:const Icon(Icons.add),
),
);
}
// Method to increment counter
void _increment(){
// Must call setState to trigger UI update
setState((){
_counter++;
});
}
// 4. didUpdateWidget - Called when parent Widget rebuilds
@override
void didUpdateWidget(CounterApp oldWidget){
super.didUpdateWidget(oldWidget);
}
// 5. dispose - Clean up resources
@override
void dispose(){
// Cancel timer to prevent memory leaks
_timer?.cancel();
super.dispose();
}
}
* * *
## Proper Usage of setState
In StatefulWidget, you must use setState to notify Flutter that the state has changed.
### Correct Usage
## Example: Correct setState Usage
// Correct: Update state within setState
void _increment(){
setState((){
_counter++;
});
}
// Correct: State updates not related to UI don't require setState
void _someInternalLogic(){
// Internal logic, doesn't affect UI
_calculateSomething();
}
// Correct: Update state after asynchronous operations
Future _loadData() async {
final data = await fetchData();
setState((){
_items = data;
});
}
### Incorrect Usage
## Example: Incorrect setState Usage
// Incorrect: Modify state but don't call setState
void _increment(){
_counter++;// State changed, but UI won't update!
}
// Incorrect: Call setState inside build method
@override
Widget build(BuildContext context){
// Never call setState inside build!
setState((){
_counter++;// This causes infinite loop
});
return Text('$_counter');
}
> setState triggers a rebuild of the build method on the next frame draw.
>
>
> Frequent calls to setState or calling setState inside the build method can cause performance issues.
* * *
## How to Choose
When developing, choose the appropriate Widget type based on actual needs:
### Choose StatelessWidget When
* The appearance of the Widget does not depend on any mutable state
* All needed data is passed through constructor from parent Widget
* The Widget does not need to respond to user interaction
* You want optimal performance
### Choose StatefulWidget When
* The Widget needs to maintain internal state
* Need to respond to user input (taps, scrolls, etc.)
* Need to respond to data changes (e.g., network request returns)
* Need to control animations
YouTip