InheritedWidget
ปัญหาที่แก้
หัวข้อที่มีชื่อว่า “ปัญหาที่แก้”การส่ง data ลง tree ลึก ๆ ด้วยมือ — ผ่านทุก constructor — เป็นเรื่องทรมาน นี่คือ “prop drilling” และผูก widget ตรงกลางทุกตัวเข้ากับ data ที่ไม่ได้ใช้
InheritedWidget คือคำตอบ built-in ของ Flutter คุณวางไว้สูงใน tree แล้ว descendant ตัวไหนก็อ่านค่าได้ ตรง ๆ ผ่าน context ไม่ว่าจะลึกแค่ไหน โดยไม่มี widget ตรงกลางสักตัวต้องรู้เรื่อง Theme, MediaQuery, Navigator และ Provider ล้วนเป็น InheritedWidget — คุณใช้กันมาตลอดอยู่แล้ว
descendant อ่านค่าอย่างไร
หัวข้อที่มีชื่อว่า “descendant อ่านค่าอย่างไร”descendant เรียก dependOnInheritedWidgetOfExactType ซึ่งมักถูกห่อไว้ใน static method of(context) ตามธรรมเนียม:
class ThemeConfig extends InheritedWidget { const ThemeConfig({super.key, required this.color, required super.child}); final Color color;
// ธรรมเนียม: static `of` ที่ register ผู้เรียกเป็น dependent static ThemeConfig of(BuildContext context) { final result = context.dependOnInheritedWidgetOfExactType<ThemeConfig>(); assert(result != null, 'No ThemeConfig found in context'); return result!; }
// เรียกเมื่อ ThemeConfig ใหม่มาแทนตัวเก่า: dependent ควร rebuild ไหม? @override bool updateShouldNotify(ThemeConfig oldWidget) => color != oldWidget.color;}
// ที่ไหนก็ได้ที่อยู่ต่ำกว่า:final color = ThemeConfig.of(context).color;มีสองกลไกที่สำคัญตรงนี้ dependOnInheritedWidgetOfExactType ทำสองอย่างพร้อมกัน: หา ancestor ที่ใกล้ที่สุดของ type นั้น (การ lookup ขึ้น element tree ที่เร็วและ cache ไว้) และ register element ที่เรียกให้เป็น dependent ส่วน updateShouldNotify ตัดสินว่า เมื่อ inherited widget ถูก rebuild ด้วย data ใหม่ dependent จำเป็นต้อง rebuild จริงไหม
rebuild เฉพาะ dependent
หัวข้อที่มีชื่อว่า “rebuild เฉพาะ dependent”นี่คือผลตอบแทน เมื่อ InheritedWidget update และ updateShouldNotify คืน true Flutter จะ rebuild เฉพาะ widget ที่เรียก of(context) — ไม่ใช่ทั้ง subtree widget ตรงกลางที่ไม่เคย depend ก็ไม่ถูกแตะ
flowchart TB iw["InheritedWidget (color เปลี่ยน)"] --> a["Widget A (ไม่ได้ depend) ไม่ rebuild"] iw --> b["Widget B เรียก of(context) rebuild"] iw --> c["Widget C (ไม่ได้ depend) ไม่ rebuild"]
การ rebuild แบบเจาะจงนั้นคือเหตุผลที่ InheritedWidget scale ได้: การอ่านคือ lookup ขึ้นบนที่ราคาถูก และ update จะกระเพื่อมไปถึงแค่ dependent จริง ๆ ทุก state solution ระดับสูงกว่านี้ ล้วนเป็นกลไกนี้บวก ergonomics อยู่ข้างใต้