Flutter Daily: Understanding Keys and When to Use Them

Understanding Keys and When to Use Them

What You’ll Learn

Keys are Flutter’s way of preserving widget state when the widget tree changes. Most of the time you don’t need them, but when you do, they’re essential for preventing confusing bugs.

Why Keys Matter

When Flutter rebuilds the widget tree, it uses widget types and positions to determine which widgets changed. But sometimes widgets of the same type swap positions—like when you reorder a list. Without keys, Flutter might lose track of which widget is which, causing state to attach to the wrong widget.

Example: The Problem Without Keys

class ReorderableList extends StatefulWidget {
  @override
  _ReorderableListState createState() => _ReorderableListState();
}

class _ReorderableListState extends State<ReorderableList> {
  List<String> items = ['Apple', 'Banana', 'Cherry'];

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        return StatefulTile(text: items[index]);
      },
    );
  }
}

class StatefulTile extends StatefulWidget {
  final String text;
  
  const StatefulTile({required this.text});

  @override
  _StatefulTileState createState() => _StatefulTileState();
}

class _StatefulTileState extends State<StatefulTile> {
  bool isChecked = false;

  @override
  Widget build(BuildContext context) {
    return CheckboxListTile(
      title: Text(widget.text),
      value: isChecked,
      onChanged: (val) => setState(() => isChecked = val ?? false),
    );
  }
}

The Bug: If you check “Apple” and then remove it from the list, “Banana” might appear checked instead. Flutter reuses the widget state for the widget in position 0, not the widget with the “Apple” data.

The Solution: Add Keys

itemBuilder: (context, index) {
  return StatefulTile(
    key: ValueKey(items[index]), // Add this!
    text: items[index],
  );
}

Now Flutter tracks each tile by its content value, not just its position.

Types of Keys

ValueKey: Use when each widget has a unique data value

key: ValueKey(user.id)

ObjectKey: Use when you have a unique object

key: ObjectKey(product)

UniqueKey: Creates a key that’s never equal to another (rarely needed)

key: UniqueKey()

GlobalKey: Gives access to widget state from anywhere (use sparingly!)

final _formKey = GlobalKey<FormState>();
// Later: _formKey.currentState?.validate()

Try It Yourself

Create a simple to-do list where you can:

  1. Add items with a checkbox
  2. Remove items by tapping a delete icon
  3. Notice the state bug without keys
  4. Fix it by adding ValueKey with the item text

Pay attention to what happens to checkbox state when you delete items with and without keys.

Tip of the Day

When to use keys: You need keys when you have a list of stateful widgets that can be reordered, inserted, or removed. For stateless widgets or widgets that never change order, you can skip keys. If you see state “jumping” to the wrong widget, that’s your sign to add keys!