Understanding the power of Keys in Flutter
A Key is an identifier for widgets, elements and semantic nodes. They are the ones that are used to preserve the state when widgets move around the widget tree. A new widget will only be used to update an existing element if its key is the same as the key of the current widget associated with the element. Keys must be unique amongst the elements with the same parent.
When to use Keys?
Consider a widget tree with multiple widgets of the same type. An identification mechanism is required by the Flutter framework to identify which widget correlates to what kind of information and state. Here, the role of a Flutter key comes into play. A key uniquely identifies a widget amongst its siblings in the widget tree.
They are crucial among the widget children such as Listview or Stateful widgets whose data keeps changing order or when the state of a widget needs to be preserved across rebuilds.
Keys aren’t needed if the entire widget subtree is stateless
Scenario: A List with Reorderable Items
In this example, we will understand the use of Keys . Suppose that we have a list of reorderable items for a ToDo app. If we consider this case without the use of keys, there might be a situation where flutter might get confused about which item is which, leading to unexpected behaviour and loss of state of some items. So, this situation can be avoided by the use of keys.
Let’s start with the implementation of this without use of keys:
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('Reorderable List Example')),
body: ReorderableList(),
),
);
}
}
class ReorderableList extends StatefulWidget {
@override
_ReorderableListState createState() => _ReorderableListState();
}
class _ReorderableListState extends State<ReorderableList> {
List<String> items = ['Item 1', 'Item 2', 'Item 3'];
@override
Widget build(BuildContext context) {
return ReorderableListView(
onReorder: (oldIndex, newIndex) {
if (newIndex > oldIndex) {
newIndex -= 1;
}
setState(() {
final item = items.removeAt(oldIndex);
items.insert(newIndex, item);
});
},
children: items.map((item) {
return ListTile(
title: Text(item),
);
}).toList(),
);
}
}
In the above example, the reordering of ListTile items might not occur correctly because Flutter cannot uniquely identify each ‘ListTile’ item.
The UI might not update as expected due to the loss of state of some items.
Let us try the same thing with use of keys:
Now, let’s add keys to ensure that Flutter correctly identifies each ListTile
:
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('Reorderable List Example')),
body: ReorderableList(),
),
);
}
}
class ReorderableList extends StatefulWidget {
@override
_ReorderableListState createState() => _ReorderableListState();
}
class _ReorderableListState extends State<ReorderableList> {
List<String> items = ['Item 1', 'Item 2', 'Item 3'];
@override
Widget build(BuildContext context) {
return ReorderableListView(
onReorder: (oldIndex, newIndex) {
if (newIndex > oldIndex) {
newIndex -= 1;
}
setState(() {
final item = items.removeAt(oldIndex);
items.insert(newIndex, item);
});
},
children: items.map((item) {
return ListTile(
key: ValueKey(item),
title: Text(item),
);
}).toList(),
);
}
}
Now, we have used ValueKey in the above example as stated inside the ListTile item, with the help of which Flutter is able to uniquely identify each element of the reordered list based on its value.
This will ensure that Flutter will maintain the correct state of each item when the items are reordered.
Working Mechanism of Flutter Keys
Flutter framework works tirelessly to maintain a smooth and reactive user interface. But did you ever wonder what empowers Flutter to ‘update’ appropriately and render an efficient UI experience? Yes, right! its our keys.
Flutter maintains two trees: the Element Tree and the Widget Tree. With each rebuild, the trees go through the process of widget matching, which checks whether the new widget from the same parent, built from the same location in your code, matches the type and key of the previous widget.If they match, the framework updates the existing widget with the new widgets. This is the secret that Flutter uses to unfailingly map the right data to the corresponding widget after the tree’s reconstruction.
Types of Keys in Flutter
- Value Key: The value key is used when the assignment we have to make is something constant. For example, in the To-Do List the text entered is the value.
- Object Key: An object Key uses an object to identify a widget. where object is combination of two or more fields is unique for each data combination.
- Unique Key: In the situation where the children do not have unique values or don`t have a value at all, then it is used to identify each child.It is useful when you need a widget to be completely rebuilt and ensure that it is not reused.
- Global Key: The global key can be used to access the state of another widget from anywhere in the widget tree and is a unique key across the app.It is typically used when you need to access the state of a widget or perform operations on it from outside its subtree.
Conclusion
Following along with this article you would’ve successfully got more insights about the importance of keys, the relationship keys share with widgets .
Keys are an integral part of the Flutter framework that have robust mechanisms allowing to develop interactive interfaces with terrific speed.This article covered the advantages and various scenarios of its implementation and its usage in case of conflicting situations.
Here to make the community stronger by sharing our knowledge. Follow me and my team to stay updated on the latest and greatest in the web & mobile tech world.
Ref: