Keys
ปัญหาที่ key แก้
หัวข้อที่มีชื่อว่า “ปัญหาที่ key แก้”จำ reconciliation ได้ไหม: เมื่อ rebuild Flutter match widget ใหม่แต่ละตัวกับ element ที่มีอยู่ ด้วยตำแหน่งและ type ปกติแล้วนั่นถูกต้องพอดี แต่ใน list ของ stateful widget ที่ type เดียวกัน การ match ด้วยตำแหน่งจะพังเมื่อ item ย้ายที่
ลองนึกถึง TodoItem สองตัว (แต่ละตัว stateful แต่ละตัวถือ เช่น state ของ checkbox) สลับลำดับกันใน list Flutter เห็นว่า “ตำแหน่ง 0 ยังเป็น TodoItem, ตำแหน่ง 1 ยังเป็น TodoItem” — type และตำแหน่งตรงกัน — Flutter จึงเก็บแต่ละ element (พร้อม state ของ element นั้น) ไว้ที่เดิม ข้อมูล ย้ายแต่ state ไม่ย้าย ผลคือ คุณ reorder list แต่ checkbox ยังติดอยู่ผิดแถว
flowchart LR
subgraph before["ก่อน swap"]
a0["item A (checked)"] --- a1["item B"]
end
subgraph after["หลัง swap, ไม่มี key"]
b0["item B
แต่ยังโชว์ checked"] --- b1["item A
ตอนนี้ unchecked"]
end
before -->|state ติดกับตำแหน่ง| after key ให้ identity แก่ element
หัวข้อที่มีชื่อว่า “key ให้ identity แก่ element”key บอก Flutter ว่า “identity ของ element นี้คือ X ไม่ใช่แค่ตำแหน่งของตัวเอง” ตอนนี้ เมื่อ match widget ใหม่กับ element Flutter จะ match ด้วย key — state จึงตาม widget ไปแม้ widget จะย้ายที่
// ให้แต่ละ item มี key ที่เสถียรจากข้อมูลของตัวเอง:return ListView( children: [ for (final todo in todos) TodoItem(key: ValueKey(todo.id), todo: todo), ],);ด้วย ValueKey(todo.id) การ swap list จะ reorder element ให้ตรงกัน — state ของ TodoItem แต่ละตัวเดินทางไปกับ id ของตัวเอง หลักคิดคือ: คุณต้องใช้ key เมื่อมี list ของ stateful widget ที่ลำดับหรือสมาชิกเปลี่ยนได้ list ที่เป็น stateless แทบไม่ต้องใช้
key สี่แบบ
หัวข้อที่มีชื่อว่า “key สี่แบบ”| Key | identity อ้างอิงจาก | ใช้เมื่อ |
|---|---|---|
ValueKey(v) | ค่าหนึ่ง (id, string) | item ส่วนใหญ่ใน list — ค่าข้อมูลที่เสถียรระบุแต่ละตัว |
ObjectKey(o) | object identity | สิ่งที่ระบุตัวตนเป็น object ไม่ใช่ค่าธรรมดา |
UniqueKey() | unique เสมอ | อยากบังคับให้ได้ element ใหม่ (ทิ้ง state เดิม) ทุก build |
GlobalKey() | unique ทั้งแอป | ต้องเข้าถึง state ของ widget หรือ context ของตัวเองจากที่อื่น (ใช้เท่าที่จำเป็น) |
GlobalKey เป็นตัวหนัก: ระบุ widget อย่าง unique ทั้งแอปและให้คุณเข้าถึง State ของ widget นั้นได้ (เช่น formKey.currentState!.validate()) ทรงพลังก็จริงแต่แพงและ misuse ง่าย — เลือก local key ก่อน เว้นแต่คุณต้องการ cross-tree access จริง ๆ