1

Since the element tree maps its elements to widgets in the widget tree by type, if a new widget replaces an old widget, and that new widget is of the same type as the old widget, the element in the element tree that corresponded to the old widget now gets assigned to the new widget. However, if we use keys, the elements in the element tree get mapped to widgets in the widget tree by both type and key, which eliminates the problem of the states of old widgets being reused as the states of new widgets when the old and new widgets are of the same type.

Why doesn't Flutter create a key for elements by default, and instead requires us to specify a key?

Joel Castro
  • 485
  • 6
  • 20

1 Answers1

1

First, I want to correct that sentence:

Why doesn't Flutter create a key for elements by default

Flutter actually does create a Key by default for all widgets, from the official documentation of key:

If the runtimeType and key properties of the two widgets are operator==, respectively, then the new widget replaces the old widget by updating the underlying element (i.e., by calling Element.update with the new widget).

so by default, the Key of a widget is related directly to its runtimeType, and what causes the issue in updating the state, where two widgets or more with the same Key (which we said is the same, and based on the widget runtimeType) get conflicted which causes that behavior.

You might be asking now, why Flutter even uses the runtimeType, why it doesn't use something like the hashcode or uuid or some Random() for example as a Key...

and the answer is, that when we add our widget to the widget tree and try to update its state, Flutter doesn't take off the whole widget from the tree and insert it again, it looks up for something that has that key, which is the widget using it, then compare the State objects, then replace one with the other.

The purpose of that algorithm which works like this is to get the most performant and lightweight state update, which makes Flutter rebuilds widgets very fast.

Read more from this, and this.

in the cases where this causes the weird behavior of an old widget to get updated with a new widget, Flutter offers multiple Key solutions so that the framework knows that every widget is separated from the other one even if they have the same runtimeType, which is UniqueKey(), GlobalKey(), valueKey(), PageStorageKey()...

and every single one is different than the other and has its best use case.

as for the example of the old widget getting updated by a new one on the same screen, can be fixed by only assigning any key from those, but the ValueKey() which returns a Key based on a value of any object like ValueKey(1) as an example, or UniqueKey() where UniqueKey() == UniqueKey() is always false are just enough.

In another case, where you will use the same widget in two different screens/routes in your app, and you want them to have the same state, a GlobalKey() will fit in that case.

In another case where you have multiple scrollable widgets like ListView.builder() or a SingleChildScrollView()..., and you want to scroll to some position then navigate or change tabs (as an example)..., and the scroll position gets remembered when you get back to it, then the PageStorageKey() will fit that case.

You can read more about keys from the :

Official documentation

And this

Gwhyyy
  • 7,554
  • 3
  • 8
  • 35