ข้ามไปยังเนื้อหา

Keys

จำ 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, state ถูก match ด้วยตำแหน่งและติดอยู่ที่เดิม

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 แทบไม่ต้องใช้

Keyidentity อ้างอิงจากใช้เมื่อ
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 จริง ๆ

คุณต้องใช้ key มากที่สุดเมื่อไร?
อะไรผิดพลาดเมื่อ reorder stateful list item โดยไม่มี key?
จะใช้ key แบบไหนให้แต่ละ item ใน list มี identity ที่เสถียรจาก id ของข้อมูล?
อะไรพิเศษ (และแพง) เกี่ยวกับ GlobalKey?