159 lines
3.9 KiB
Markdown
159 lines
3.9 KiB
Markdown
# Flutter Widget Lifecycle: A Comprehensive Guide
|
|||
|
|
|
||
|
|
Understanding the lifecycle of widgets in Flutter is crucial for managing state and resources effectively. This guide covers the lifecycle of stateful widgets and the importance of keys.
|
||
|
|
|
||
|
|
## 1. Stateful Widget Lifecycle
|
||
|
|
|
||
|
|
Stateful widgets go through several lifecycle methods. Here's the order of execution:
|
||
|
|
|
||
|
|
1. `createState()`
|
||
|
|
2. `initState()`
|
||
|
|
3. `didChangeDependencies()`
|
||
|
|
4. `build()`
|
||
|
|
5. `didUpdateWidget()`
|
||
|
|
6. `setState()`
|
||
|
|
7. `deactivate()`
|
||
|
|
8. `dispose()`
|
||
|
|
|
||
|
|
### Example:
|
||
|
|
|
||
|
|
```dart
|
||
|
|
import 'package:flutter/material.dart';
|
||
|
|
|
||
|
|
class LifecycleWidget extends StatefulWidget {
|
||
|
|
final String name;
|
||
|
|
|
||
|
|
LifecycleWidget({Key? key, required this.name}) : super(key: key);
|
||
|
|
|
||
|
|
@override
|
||
|
|
_LifecycleWidgetState createState() => _LifecycleWidgetState();
|
||
|
|
}
|
||
|
|
|
||
|
|
class _LifecycleWidgetState extends State<LifecycleWidget> {
|
||
|
|
@override
|
||
|
|
void initState() {
|
||
|
|
super.initState();
|
||
|
|
print('initState');
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
void didChangeDependencies() {
|
||
|
|
super.didChangeDependencies();
|
||
|
|
print('didChangeDependencies');
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
void didUpdateWidget(LifecycleWidget oldWidget) {
|
||
|
|
super.didUpdateWidget(oldWidget);
|
||
|
|
print('didUpdateWidget');
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
void setState(VoidCallback fn) {
|
||
|
|
super.setState(fn);
|
||
|
|
print('setState');
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
void deactivate() {
|
||
|
|
print('deactivate');
|
||
|
|
super.deactivate();
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
void dispose() {
|
||
|
|
print('dispose');
|
||
|
|
super.dispose();
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
print('build');
|
||
|
|
return Text(widget.name);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 2. Explanation of Lifecycle Methods
|
||
|
|
|
||
|
|
- `createState()`: Called when the StatefulWidget is inserted into the widget tree.
|
||
|
|
- `initState()`: Called once when the widget is inserted into the widget tree.
|
||
|
|
- `didChangeDependencies()`: Called when a dependency of this State object changes.
|
||
|
|
- `build()`: Called every time the widget needs to be rebuilt.
|
||
|
|
- `didUpdateWidget()`: Called whenever the widget configuration changes.
|
||
|
|
- `setState()`: Called when the internal state of the widget changes.
|
||
|
|
- `deactivate()`: Called when the widget is removed from the tree.
|
||
|
|
- `dispose()`: Called when the widget is removed permanently from the widget tree.
|
||
|
|
|
||
|
|
## 3. Keys in Flutter
|
||
|
|
|
||
|
|
Keys are used to preserve state when widgets move around in the widget tree.
|
||
|
|
|
||
|
|
### Example:
|
||
|
|
|
||
|
|
```dart
|
||
|
|
import 'package:flutter/material.dart';
|
||
|
|
|
||
|
|
class KeyExample extends StatefulWidget {
|
||
|
|
@override
|
||
|
|
_KeyExampleState createState() => _KeyExampleState();
|
||
|
|
}
|
||
|
|
|
||
|
|
class _KeyExampleState extends State<KeyExample> {
|
||
|
|
List<Widget> tiles = [
|
||
|
|
StatefulColorfulTile(key: UniqueKey()),
|
||
|
|
StatefulColorfulTile(key: UniqueKey()),
|
||
|
|
];
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
return Scaffold(
|
||
|
|
body: Row(children: tiles),
|
||
|
|
floatingActionButton: FloatingActionButton(
|
||
|
|
child: Icon(Icons.swap_horiz),
|
||
|
|
onPressed: swapTiles,
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
swapTiles() {
|
||
|
|
setState(() {
|
||
|
|
tiles.insert(1, tiles.removeAt(0));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class StatefulColorfulTile extends StatefulWidget {
|
||
|
|
StatefulColorfulTile({Key? key}) : super(key: key);
|
||
|
|
|
||
|
|
@override
|
||
|
|
_StatefulColorfulTileState createState() => _StatefulColorfulTileState();
|
||
|
|
}
|
||
|
|
|
||
|
|
class _StatefulColorfulTileState extends State<StatefulColorfulTile> {
|
||
|
|
late Color myColor;
|
||
|
|
|
||
|
|
@override
|
||
|
|
void initState() {
|
||
|
|
super.initState();
|
||
|
|
myColor = Colors.primaries[
|
||
|
|
DateTime.now().microsecondsSinceEpoch % Colors.primaries.length];
|
||
|
|
}
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
return Container(
|
||
|
|
color: myColor,
|
||
|
|
child: Padding(
|
||
|
|
padding: EdgeInsets.all(70.0),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
In this example, using `UniqueKey()` ensures that each tile maintains its state (color) even when their positions are swapped.
|
||
|
|
|
||
|
|
## Conclusion
|
||
|
|
|
||
|
|
Understanding the widget lifecycle and proper use of keys is essential for managing state and optimizing performance in Flutter applications. By leveraging these concepts, you can create more efficient and predictable widget behaviors.
|