What are Keys in the Stateless widgets class?

DartFlutter

Dart Problem Overview


In the flutter docs there's sample code for a stateless widget subclass as shown:

class GreenFrog extends StatelessWidget {
  const GreenFrog({ Key key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Container(color: const Color(0xFF2DBD3A));
  }
}

and this

class Frog extends StatelessWidget {
  const Frog({
    Key key,
    this.color: const Color(0xFF2DBD3A),
    this.child,
  }) : super(key: key);

  final Color color;

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return new Container(color: color, child: child);
  }
}

What is a key and when should this super constructor be used? It seems like if you have your own constructor you must have {Key key} why? I've seen other examples where the super keyword is not used so this is where my confusion is.

Dart Solutions


Solution 1 - Dart

TLDR: All widgets should have a Key key as optional parameter or their constructor. Key is something used by flutter engine at the step of recognizing which widget in a list as changed.


It is useful when you have a list (Column, Row, whatever) of widgets of the same type that can potentially get removed/inserted.

Let's say you have this (code not working, but you get the idea) :

AnimatedList(
  children: [
    Card(child: Text("foo")),
    Card(child: Text("bar")),
    Card(child: Text("42")),
  ]
)

Potentially, you can remove any of these widgets individually with a swipe.

The thing is, our list has an animation when a child is removed. So let's remove "bar".

AnimatedList(
  children: [
    Card(child: Text("foo")),
    Card(child: Text("42")),
  ]
)

The problem: Without Key, flutter won't be able to know if the second element of your Row disappeared. Or if it's the last one that disappeared and the second has its child change.

So without Key, you could potentially have a bug where your leave animation will be played on the last element instead!


This is where Key takes place.

If we start our example again, using key we'd have this :

AnimatedList(
  children: [
    Card(key: ObjectKey("foo"), child: Text("foo")),
    Card(key: ObjectKey("bar"), child: Text("bar")),
    Card(key: ObjectKey("42"), child: Text("42")),
  ]
)

notice how the key is not the child index but something unique to the element.

From this point, if we remove "bar" again, we'll have

AnimatedList(
  children: [
    Card(key: ObjectKey("foo"), child: Text("foo")),
    Card(key: ObjectKey("42"), child: Text("42")),
  ]
)

Thanks to key being present, flutter engine now knows for sure which widget got removed. And now our leave animation will correctly play on "bar" instead of "42".

Solution 2 - Dart

What are Keys?

Keys are IDs for widgets. All widgets have them, not just StatelessWidgets. They are used by the Element tree to determine if a widget can be reused or if it needs to be rebuilt. When no key is specified (the usual case), then the widget type is used to determine this.

Why use Keys?

Keys are useful for maintaining state when the number or position of widgets changes. If there is no key then the Flutter framework can get confused about which widget changed.

When to use Keys?

Only use them when the framework needs your help to know which widget to update.

Most of the time you don't need to use keys. Since keys are mostly only useful for maintaining state, if you have a stateless widget whose children are all stateless, then there is no need to use a key on it. It won't hurt to use a key in this case, but it also won't help.

There are some micro-optimizations you can make using keys. See this article.

Where to use Keys?

Put the key at the part of the widget tree where the reordering or addition/deletion is taking place. For example, if you are reordering the items of a ListView whose children are ListTile widgets, then add the keys to the ListTile widgets.

What kind of Keys to use?

A key is just an id, but the kind of ID you use can vary.

ValueKey

A ValueKey is a local key that takes a simple value like a string or integer.

ObjectKey

If you widget is displaying more complex data than a single value, then you can use an ObjectKey for that widget.

UniqueKey

This type of key is guaranteed to give you a unique ID every time. If you use it, though, do NOT put it in the build method. Otherwise your widget will never have the same ID and so the Element tree will never find a match to reuse.

GlobalKey

GlobalKeys can be used to maintain state across your app, but use them sparingly because they are similar to global variables. It is often preferable to use a state management solution instead.

Examples of using Keys

References

Solution 3 - Dart

Key is object that is used to identify a widget uniquely.

They are used to access or restore state In a StatefulWidget (Mostly we don't need them at all if our widget tree is all Stateless Widgets). There are various types of key that I will try to explain on the basis of usage.

Purpose (key types)

1. Mutate the collection i.e. remove / add / reorder item to list in stateful widget like draggable todo list where checked items get removed

➡️ ObjectKey, ValueKey & UniqueKey

2. Move widget from one Parent to another preserving it's state.

➡️ GlobalKey

3. Display same Widget in multiple screens and holding its state.

➡️ GlobalKey

4. Validate Form.

➡️ GlobalKey

5. You want to give a key without using any data.

➡️ UniqueKey

6. If you can use a certain fields of data like UUID of users as unique Key.

➡️ ValueKey

7. If you do not have any unique field to use as key but object itself is unique.

➡️ ObjectKey

8. If you have multiple Forms or Multiple Widgets of the same type that need GlobalKey.

➡️ GlobalObjectKey, LabeledGlobalKey whichever is appropriate, similar logic to ValueKey and ObjectKey

❌ Do not use random string/number as key, it defeats the purpose of keys ❌

Solution 4 - Dart

The Key is an optional parameter needed to preserve state in your widget tree, you have to use them if you want to move a collection of elements in your tree and preserve the state of them.

The best explanation can be found in this video by Google When to Use Keys - Flutter Widgets 101 Ep. 4

Solution 5 - Dart

With Dart 2.12 or later, add ? after Key to make it optional if you want.

class Frog extends StatelessWidget {
  const Frog({
    Key? key,
    this.color: const Color(0xFF2DBD3A),
    this.child,
  }) : super(key: key);

  final Color color;

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return new Container(color: color, child: child);
  }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDanT29View Question on Stackoverflow
Solution 1 - DartRémi RousseletView Answer on Stackoverflow
Solution 2 - DartSuragchView Answer on Stackoverflow
Solution 3 - DarterluxmanView Answer on Stackoverflow
Solution 4 - Dartd0xzenView Answer on Stackoverflow
Solution 5 - DartAzamat Ali View Answer on Stackoverflow