What is the Key

In the official line:

Key is used as an identifier for the Widget, Element, and SemanticsNode, and is only used to update the status of widgets with the same Widget ->key.

Key subclasses include LocalKey and GlobalKey.

LocalKey

Take a look at the definition of LocalKey:

abstract class LocalKey extends Key {
  const LocalKey() : super.empty();
}
Copy the code

LocalKey defines the initialization function, which defaults to null.

LocalKey subclass containing ValueKey/ObjectKey/UniqueKey, as shown in figure:

ValueKey

ValueKey, as the name implies, compares values

Let’s look at the key function

@override bool operator ==(Object other) { if (other.runtimeType ! = runtimeType) return false; return other is ValueKey<T> && other.value == value; }Copy the code

It is also easy to use when we want the system to determine whether we can refresh based on the key we have given it.

TextField(
          key: ValueKey('value1'),
        ),
        TextField(
          key: ValueKey('value2'),),Copy the code

When we swap the order, the TextField values are swapped, so our key takes the value away.

TextField(
  key: ValueKey('value2'),
),
TextField(
  key: ValueKey('value1'),),Copy the code

What if we use another class to pass values? We’re passing in class Student as value.


class Student {
  final String name;

  Student(this.name);

  @override
  int get hashCode => name.hashCode;
}

TextField(
  key: ObjectKey(Student('Lao wang')),
),
TextField(
  key: ObjectKey(Student('Lao wang'))),Copy the code

No error is reported after refresh, normal use.

Let’s take a look at this after Student overrides the == operator, so let’s change the Student code a little bit

class Student {
  final String name;

  Student(this.name);

  @override
  int get hashCode => name.hashCode;

  @override
  bool operator= = (Object other) =>
      identical(this, other) ||
      other is Student &&
          runtimeType == other.runtimeType &&
          name == other.name;
}
Copy the code

Then hot reload, error

If multiple keyed nodes exist as children of another node, they must have unique keys.
Copy the code

Student == (Key = Value); Student == (Key = Value);

ObjectKey

How does this key compare objects? Let’s look at the source code;

  @override
  bool operator= = (Object other) {
    if(other.runtimeType ! = runtimeType)return false;
    return other is ObjectKey
        && identical(other.value, value);
  }
Copy the code

The official display of comparison type, when the type is inconsistent, it is judged as not through one object, if the other is also ObjectKey, then judge whether the address is the same, only the same address is judged as the same object.

Test data;

class Student {
  final String name;

  Student(this.name);

  @override
  int get hashCode => name.hashCode;

  @override
  bool operator= = (Object other) =>
      identical(this, other) ||
      other is Student &&
          runtimeType == other.runtimeType &&
          name == other.name;
}


TextField(
    key: ObjectKey(Student('Lao wang')),
  ),
  TextField(
    key: ObjectKey(Student('Lao wang'))),Copy the code

No error is reported after the interface is refreshed.

ObjectKey has been modified slightly

   _student = Student('Lao wang');

  TextField(
    key: ObjectKey(_student),
  ),
  TextField(
    key: ObjectKey(_student),
  ),
Copy the code

Error after refresh, same key exists.

If multiple keyed nodes exist as children of another node, they must have unique keys.
Copy the code

UniqueKey

Generating a different value every time, when we need a new value every time we refresh, is exactly what this is all about.

Each time we refresh, we generate a new color and fade in and out.

AnimatedSwitcher(
  duration: Duration(milliseconds: 1000),
  child: Container(
    key: UniqueKey(),
    height: 100,
    width: 100,
    color: Colors.primaries[count % Colors.primaries.length],
  ),
)
Copy the code

Effect:

GlobalKey & GlobalObjectKey

As a key for global use, we can usually use GlobalKey to refresh other widgets when across widgets.

The criteria for GlobalObjectKey and ObjectKey equality are consistent. GlobalObjectKey extends GlobalKey, specifying the State to inherit via GlobalKey

>, and the class that implements the StatefulWidget interface. You can then get the currentState with globalkey.currentstate, and then call state.setstate ((){}) to complete marking the current widget as dirty, and refresh the current widget in the next frame.

example

Click the button to refresh the background color of the widget.

GlobalKey _key = GlobalKey();
_Container(_key),
OutlineButton(
  child: Text('Global Key Refresh'),
  onPressed: () {
    _key.currentState.setState(() {});
  },
Copy the code

Click globalKey to refresh the local widget, and click the lower right corner to refresh the entire page. As you can see, only the bottom widget changes color when part of the page is refreshed, while the entire page is refreshed.

Effect:

reference

  • Sample code base
  • The official source

The article summary

Dart asynchrony and multithreading

Insight into state management –ScopeModel

Learn more about Flutter management –Redux

Detailed explanation of Flutter (iii. In-depth understanding of state management –Provider)

4. Deeper understanding of state management –BLoC

A detailed explanation of Flutter

1, Learn about the Stream

7. Understand the principle of drawing deeply

Detailed explanation of Flutter

Project recommend

  • A cool loading animation library
  • Flutter100 + component usage examples
  • Flutter entry to advanced ebook

The public,