
Parameter key
dapat ditemukan di hampir setiap konstruktor widget, tetapi parameter ini jarang digunakan dalam pengembangan. Keys
mempertahankan status saat memindahkan widget di pohon widget. Dalam praktiknya, ini berarti bahwa mereka dapat berguna untuk menyimpan lokasi gulir pengguna atau menyimpan kondisi ketika koleksi berubah.
Artikel ini diadaptasi dari video berikut. Jika Anda lebih suka mendengarkan / menonton daripada membaca, maka video akan memberi Anda materi yang sama.
Sebagian besar waktu ... Anda tidak perlu keys
. Secara umum, tidak ada salahnya menambahkannya, tetapi ini juga tidak perlu, karena mereka hanya terjadi sebagai kata kunci baru atau ketik deklarasi di kedua sisi variabel baru (saya berbicara tentang Anda, Map<Foo, Bar> aMap = Map<Foo, Bar>()
).
Tetapi jika Anda menemukan bahwa Anda menambahkan, menghapus, atau mengatur ulang widget dalam koleksi yang berisi beberapa status dan jenis yang sama, maka Anda harus memperhatikan keys
!
Untuk menunjukkan mengapa Anda memerlukan keys
saat mengubah koleksi widget, saya menulis aplikasi yang sangat sederhana dengan dua widget berwarna yang mengubah tempat ketika sebuah tombol diklik:

Dalam versi aplikasi ini, saya memiliki dua widget stateless dengan warna acak ( StatelessWidget
) di widget Row
dan PositionedTiles dengan status ( StatefulWidget
) untuk menyimpan urutan widget warna di dalamnya. Ketika saya mengklik tombol FloatingActionButton
di bagian bawah, widget warna dengan benar mengubah tempat mereka dalam daftar:
void main() => runApp(new MaterialApp(home: PositionedTiles())); class PositionedTiles extends StatefulWidget { @override State<StatefulWidget> createState() => PositionedTilesState(); } class PositionedTilesState extends State<PositionedTiles> { List<Widget> tiles = [ StatelessColorfulTile(), StatelessColorfulTile(), ]; @override Widget build(BuildContext context) { return Scaffold( body: Row(children: tiles), floatingActionButton: FloatingActionButton( child: Icon(Icons.sentiment_very_satisfied), onPressed: swapTiles), ); } swapTiles() { setState(() { tiles.insert(1, tiles.removeAt(0)); }); } } class StatelessColorfulTile extends StatelessWidget { Color myColor = UniqueColorGenerator.getColor(); @override Widget build(BuildContext context) { return Container( color: myColor, child: Padding(padding: EdgeInsets.all(70.0))); } }
Tetapi jika kita menambahkan status ke widget warna kita (membuatnya StatefulWidget
) dan menyimpan warna di dalamnya, maka ketika kita mengklik tombol itu tampak seolah-olah tidak ada yang terjadi:

List<Widget> tiles = [ StatefulColorfulTile(), StatefulColorfulTile(), ]; ... class StatefulColorfulTile extends StatefulWidget { @override ColorfulTileState createState() => ColorfulTileState(); } class ColorfulTileState extends State<ColorfulTile> { Color myColor; @override void initState() { super.initState(); myColor = UniqueColorGenerator.getColor(); } @override Widget build(BuildContext context) { return Container( color: myColor, child: Padding( padding: EdgeInsets.all(70.0), )); } }
Sebagai penjelasan: kode di atas bermasalah karena tidak menunjukkan pertukaran warna saat pengguna mengklik tombol. Untuk memperbaiki kesalahan ini, Anda perlu menambahkan parameter key
ke widget StatefulWidget
berwarna, dan kemudian widget akan ditukar seperti yang kita inginkan:

List<Widget> tiles = [ StatefulColorfulTile(key: UniqueKey()),
Tetapi ini hanya diperlukan jika Anda memiliki widget dengan status di subtree yang sedang Anda ubah. Jika seluruh subtree widget dalam koleksi Anda tidak memiliki status, tidak diperlukan tombol.
Itu dia! Semua dalam semua, semua yang perlu Anda ketahui untuk menggunakan keys
di Flutter
. Tetapi jika Anda ingin sedikit lebih dalam tentang apa yang terjadi ...
Memahami mengapa keys
terkadang diperlukan
Kamu masih di sini, kan? Kalau begitu datanglah lebih dekat untuk mengetahui sifat sebenarnya dari elemen tree dan widget untuk menjadi Flutter Mage! Wahahaha! Haha Haha Um, maaf.
Seperti yang Anda ketahui, di dalam setiap widget Flutter membangun elemen yang sesuai. Sama seperti Flutter membangun pohon widget, itu juga membuat pohon elemen (ElementTree). ElementTree sangat sederhana, hanya berisi informasi jenis setiap widget dan tautan ke elemen anak. Anda dapat menganggap ElementTree sebagai kerangka aplikasi Flutter Anda. Ini menunjukkan struktur aplikasi Anda, tetapi semua informasi tambahan dapat ditemukan pada tautan ke widget sumber.
Widget baris pada contoh di atas berisi satu set slot yang dipesan untuk masing-masing anak-anaknya. Ketika kami menyusun ulang widget warna di Row, Flutter berjalan di sekitar ElementTree untuk memeriksa apakah struktur kerangka aplikasi itu sama.

Validasi dimulai dengan RowElement, dan kemudian beralih ke anak-anak. ElementTree memeriksa apakah widget baru memiliki jenis dan key
sama dengan yang lama, dan jika ya, elemen memperbarui tautannya ke widget baru. Dalam versi tanpa kode, widget tidak memiliki key
, jadi Flutter hanya memeriksa jenisnya saja. (Jika ada terlalu banyak informasi pada suatu waktu, maka lihat bagan animasi di atas.)
Di bawah ElementTree untuk widget keadaan terlihat sedikit berbeda. Ada widget dan elemen, seperti sebelumnya, tetapi ada juga beberapa objek keadaan untuk widget, dan informasi warna disimpan di dalamnya, dan bukan di widget itu sendiri.

Dalam kasus widget StatefulWidget
berwarna tanpa key
, ketika saya mengubah urutan dua widget, Flutter berkeliling ElementTree, memeriksa jenis RowWidget dan memperbarui tautan. Kemudian elemen widget warna memeriksa apakah widget yang sesuai memiliki tipe yang sama dan memperbarui tautannya. Hal yang sama terjadi dengan widget kedua. Karena Flutter menggunakan ElementTree dan status terkait untuk menentukan apa yang sebenarnya ditampilkan pada perangkat Anda, dari sudut pandang kami, tampaknya widget belum ditukar!

Dalam versi kode yang diperbaiki dalam widget berwarna dengan status konstruktor, saya mendefinisikan properti key
. Sekarang, jika kita mengubah widget di Row
, maka dengan mengetiknya mereka akan cocok seperti sebelumnya, tetapi nilai key
widget warna dan elemen yang sesuai di ElementTree akan berbeda. Ini menyebabkan Flutter menonaktifkan elemen widget warna ini dan menghapus tautannya di ElementTree, mulai dari yang pertama, yang tidak cocok dengan key
.

Kemudian Flutter mencari widget di elemen Row
di ElementTree dengan key
sesuai. Jika cocok, itu menambahkan tautan ke elemen widget. Flutter tidak untuk setiap anak tanpa tautan. Sekarang Flutter akan menampilkan apa yang kita harapkan, widget warna akan berubah tempat ketika saya mengklik tombol.
Dengan demikian, keys
berguna jika Anda mengubah urutan atau jumlah widget dengan status dalam koleksi. Dalam contoh ini, saya menyimpan warnanya. Namun, seringkali kondisinya tidak begitu jelas. Memutar animasi, menampilkan input pengguna, dan menggulir lokasi - semuanya memiliki status.
Kapan saya harus menggunakan keys
?
Jawaban singkat: jika Anda perlu menambahkan keys
ke aplikasi, Anda harus menambahkannya di bagian atas subtree widget dengan status yang ingin Anda simpan.
Kesalahan umum yang saya lihat adalah orang berpikir bahwa mereka perlu mendefinisikan key
hanya untuk widget pertama dengan status, tetapi ada nuansa. Jangan percaya padaku? Untuk menunjukkan masalah yang kita hadapi, saya membungkus widget warna saya di widget Padding
, sambil meninggalkan tombol untuk widget warna.
void main() => runApp(new MaterialApp(home: PositionedTiles())); class PositionedTiles extends StatefulWidget { @override State<StatefulWidget> createState() => PositionedTilesState(); } class PositionedTilesState extends State<PositionedTiles> {
Sekarang, dengan satu sentuhan tombol, widget mendapatkan warna yang benar-benar acak!

Beginilah tampilan pohon widget dan ElementTree dengan widget Padding
ditambahkan:

Saat kami mengubah posisi widget anak, algoritme pencocokan antara elemen dan widget terlihat satu tingkat di hierarki elemen. Dalam diagram, anak-anak anak-anak digelapkan sehingga tidak ada yang mengalihkan perhatian dari tingkat pertama. Pada level ini, semuanya cocok dengan benar.

Pada tingkat kedua, Flutter memperhatikan bahwa key
elemen warna tidak cocok dengan key
widget, jadi ini menonaktifkan elemen ini, membuangnya dan menghapus semua tautan ke sana. keys
kami gunakan dalam contoh ini adalah LocalKeys
. Ini berarti bahwa ketika mencocokkan widget dengan elemen, Flutter mencari keys
hanya pada tingkat pohon tertentu.
Karena dia tidak dapat menemukan elemen widget warna pada level ini dengan tombol yang sesuai, dia membuat yang baru dan menginisialisasi keadaan baru, membuat widget berwarna oranye dalam hal ini!

Jika kami menetapkan keys
untuk widget Padding
:
void main() => runApp(new MaterialApp(home: PositionedTiles())); class PositionedTiles extends StatefulWidget { @override State<StatefulWidget> createState() => PositionedTilesState(); } class PositionedTilesState extends State<PositionedTiles> { List<Widget> tiles = [ Padding(
Flutter memperhatikan masalah dan memperbarui tautan dengan benar, seperti pada contoh sebelumnya. Urutan di alam semesta dipulihkan.

Jenis Key
harus saya gunakan?
Flutter API memberi kami pilihan beberapa kelas Key
. Jenis key
yang harus Anda gunakan tergantung pada fitur apa yang membedakan elemen yang membutuhkan keys
. Lihatlah informasi yang Anda simpan di masing-masing widget.
Pertimbangkan aplikasi Agenda berikut [1], di mana Anda dapat mengubah urutan item dalam daftar tugas berdasarkan prioritas, dan ketika selesai, Anda dapat menghapusnya.

ValueKey
Dalam hal ini, kita dapat berharap bahwa teks paragraf implementasi akan bersifat permanen dan unik. Jika demikian, maka ini mungkin kandidat yang baik untuk ValueKey
, di mana teksnya adalah "nilai".
return TodoItem( key: ValueKey(todo.task), todo: todo, onDismissed: (direction) => _removeTodo(context, todo), );
Objectkey
Atau, Anda mungkin memiliki aplikasi Buku Alamat, yang mencantumkan informasi tentang setiap pengguna. Dalam hal ini, setiap widget anak menyimpan kombinasi data yang lebih kompleks. Setiap bidang individual, misalnya, nama atau tanggal lahir, mungkin bertepatan dengan entri lain, tetapi kombinasinya unik. Dalam hal ini, ObjectKey
kemungkinan besar paling cocok.

Uniquekey
Jika Anda memiliki beberapa widget dalam koleksi dengan nilai yang sama atau jika Anda ingin memastikan bahwa setiap widget berbeda dari yang lain, maka Anda dapat menggunakan UniqueKey
. Saya menggunakan UniqueKey
dalam contoh aplikasi untuk beralih warna, karena kami tidak memiliki data konstan lain yang akan disimpan dalam widget kami, dan kami tidak tahu apa warna widget yang akan dimiliki ketika itu dibuat.
Namun, satu hal yang tidak ingin Anda gunakan sebagai key
adalah angka acak. Setiap kali widget dibuat, nomor acak baru akan dihasilkan dan Anda akan kehilangan konsistensi antara frame. Dalam skenario ini, Anda tidak boleh menggunakan keys
sama sekali!
PageStorageKeys
PageStorageKeys
adalah keys
khusus yang berisi keadaan gulir saat ini sehingga aplikasi dapat menyimpannya untuk digunakan nanti.

Globalkey
Ada dua opsi untuk menggunakan GlobalKeys
: mereka memungkinkan widget untuk mengubah orang tua di mana saja dalam aplikasi tanpa kehilangan status dan dapat digunakan untuk mengakses informasi tentang widget lain di bagian pohon widget yang sama sekali berbeda. Sebagai contoh skenario pertama, Anda dapat membayangkan bahwa Anda ingin menampilkan widget yang sama di dua layar berbeda, tetapi dengan status yang sama, agar data widget disimpan, Anda akan menggunakan GlobalKey
. Dalam kasus kedua, situasi mungkin muncul ketika Anda perlu memeriksa kata sandi, tetapi Anda tidak ingin berbagi informasi status dengan widget lain di pohon. GlobalKeys
juga dapat berguna untuk pengujian, menggunakan key
untuk mengakses widget tertentu dan meminta informasi tentang statusnya.

Seringkali (tetapi tidak selalu!) GlobalKeys
sedikit seperti variabel global. Seringkali mereka dapat diganti dengan InheritedWidgets
atau sesuatu seperti Redux, atau template BLoC.
Kesimpulan singkat
Secara umum, gunakan Keys
jika Anda ingin mempertahankan status di antara subtree widget. Ini paling sering terjadi ketika mengubah koleksi widget dari jenis yang sama. Tempatkan key
di bagian atas subtree widget yang ingin Anda simpan, dan pilih jenis key
berdasarkan data yang disimpan dalam widget.
Selamat, Anda sekarang berada di jalan untuk menjadi Flutter Mage! Oh, aku bilang pesulap? Maksud saya pesulap, seperti orang yang menulis kode sumber aplikasi ... yang hampir sama bagusnya. ... hampir.
[1] Inspirasi untuk menulis kode aplikasi Agenda yang diterima di sini
https://github.com/brianegan/flutter_architecture_samples/tree/master/vanilla
[2] Penulis menggunakan kata sorcerer
dan kemudian menambahkan surat tambahan untuknya sebelum sourcerer