InheritedWidget — คืออะไร การส่งผ่านข้อมูลในทรี และวิธีการทำงาน

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-07-02 เวลาอ่าน: 9 นาที

InheritedWidget เป็นวิดเจ็ตพิเศษใน Flutter ที่ส่งข้อมูลลงด้านล่างในทรีของวิดเจ็ตโดยไม่ต้องส่งผ่านคอนสตรัคเตอร์อย่างชัดเจน วิดเจ็ตลูกเข้าถึงข้อมูลผ่าน BuildContext และสมัครรับการอัปเดตโดยอัตโนมัติ เมื่อข้อมูลใน InheritedWidget เปลี่ยนแปลง วิดเจ็ตที่พึ่งพาทั้งหมดจะถูกสร้างใหม่ ตาม Flutter API Reference, 2025 InheritedWidget เป็นรากฐานของ Theme, MediaQuery, Localizations และไลบรารีการจัดการสถานะส่วนใหญ่

ประเด็นสำคัญ

  • InheritedWidget ส่งข้อมูลลงด้านล่างใน Widget Tree โดยไม่ต้องส่งผ่านวิดเจ็ตทุกตัวอย่างชัดเจน
  • การสมัครรับอัตโนมัติ — วิดเจ็ตที่ใช้ dependOnInheritedWidgetOfExactType จะถูกสร้างใหม่เมื่อข้อมูลเปลี่ยนแปลง
  • Theme และ MediaQuery เป็นตัวอย่างในตัวของ InheritedWidget ที่มีในทุกแอปพลิเคชัน Flutter
  • Provider และ Riverpod ถูกสร้างบน InheritedWidget และขยายความสามารถสำหรับการจัดการสถานะ
  • การใช้งานที่ถูกต้อง ต้องการการแทนที่ updateShouldNotify เพื่อป้องกันการสร้างใหม่ที่ไม่จำเป็น

InheritedWidget ใน Flutter คืออะไร?

InheritedWidget คือวิดเจ็ตที่ทำให้ข้อมูลของมันพร้อมใช้งานสำหรับผู้สืบทอดทั้งหมดใน Widget Tree แตกต่างจากวิดเจ็ตทั่วไปที่ส่งข้อมูลผ่านคอนสตรัคเตอร์ไปยังองค์ประกอบลูกเท่านั้น InheritedWidget อนุญาตให้วิดเจ็ตใด ๆ ในทรีย่อยเข้าถึงข้อมูลโดยไม่มีสายพารามิเตอร์ ซึ่งแก้ปัญหา “prop drilling” — การส่งข้อมูลผ่านวิดเจ็ตกลางจำนวนมากที่ไม่ได้ใช้ข้อมูลนี้ด้วยตัวเอง

InheritedWidget ในตัว

Flutter มี InheritedWidget ในตัวหลายตัว: Theme (รูปแบบสีและสไตล์), MediaQuery (ขนาดหน้าจอ, การวางแนว, ความหนาแน่นพิกเซล), Localizations (สตริงที่แปล), Directionality (ทิศทางข้อความ), DefaultTextStyle (สไตล์ข้อความเริ่มต้น) วิดเจ็ตเหล่านี้ถูกตั้งค่าโดยวิดเจ็ตหลักเช่น MaterialApp และพร้อมใช้งานทั่วทั้งแอปพลิเคชัน

วงจรชีวิตของ InheritedWidget

InheritedWidget ไม่มีสถานะของตัวเอง — มันเก็บข้อมูลที่ส่งผ่านคอนสตรัคเตอร์ เมื่อพาเรนต์ของ InheritedWidget ถูกสร้างใหม่ด้วยข้อมูลใหม่ เมธอด updateShouldNotify จะถูกเรียกเพื่อเปรียบเทียบข้อมูลเก่าและใหม่ ถ้าเมธอดคืนค่า true วิดเจ็ตที่พึ่งพาทั้งหมดจะถูกทำเครื่องหมายสำหรับการสร้างใหม่ นี่เป็นกลไกการอัปเดตแบบรีแอกทีฟที่เรียบง่ายแต่มีประสิทธิภาพ

การส่งผ่านข้อมูลผ่าน InheritedWidget ทำงานอย่างไร

กลไกการส่งผ่านข้อมูล ผ่าน InheritedWidget ขึ้นอยู่กับ Element Tree เมื่อวิดเจ็ตเรียก dependOnInheritedWidgetOfExactType องค์ประกอบที่เกี่ยวข้องจะลงทะเบียนการพึ่งพาบน InheritedElement เมื่อ InheritedWidget เปลี่ยนแปลง InheritedElement จะแจ้งองค์ประกอบที่พึ่งพาทั้งหมด ซึ่งจะถูกสร้างใหม่ในเฟรมถัดไป

การลงทะเบียนการพึ่งพา

เมธอด dependOnInheritedWidgetOfExactType ไม่เพียงแค่ค้นหา InheritedWidget ในทรี — มันสมัครรับการแจ้งเตือนให้กับองค์ประกอบปัจจุบัน ถ้าคุณใช้ findAncestorWidgetOfExactType แทน dependOn วิดเจ็ตจะได้รับข้อมูลแต่จะไม่ถูกสร้างใหม่เมื่อข้อมูลเปลี่ยนแปลง นี่เป็นความแตกต่างที่สำคัญ: dependOn คือการสมัครรับ ส่วน findAncestor คือการค้นหาเพียงครั้งเดียว

การเดินทรีของ InheritedWidget

เมื่อวิดเจ็ตขอ InheritedWidget Flutter จะเดินขึ้น Element Tree จากองค์ประกอบปัจจุบันไปยังราก ตรวจสอบ InheritedElement แต่ละตัวเพื่อหาชนิดที่ตรงกัน InheritedElement ตัวแรกที่ตรงกันจะถูกคืนค่า ซึ่งหมายความว่า InheritedWidget ที่ใกล้ที่สุดในทรีมีลำดับความสำคัญ — คุณสามารถแทนที่ข้อมูลในระดับที่กำหนดโดยวาง InheritedWidget ใกล้กับผู้สืบทอดมากขึ้น

dart
class ThemeData {
  final Color primaryColor;
  final TextTheme textTheme;

  const ThemeData({required this.primaryColor, required this.textTheme});
}

class MyTheme extends InheritedWidget {
  final ThemeData data;

  const MyTheme({required this.data, required Widget child}) : super(child: child);

  static MyTheme of(BuildContext context) {
    final widget = context.dependOnInheritedWidgetOfExactType<MyTheme>();
    assert(widget != null, "MyTheme not found in tree");
    return widget!;
  }

  @override
  bool updateShouldNotify(MyTheme oldWidget) => oldWidget.data != data;
}

ในตัวอย่างนี้ MyTheme ใช้เมธอดสแตติก of เพื่อให้ข้อมูลแก่ผู้สืบทอด เมธอด dependOnInheritedWidgetOfExactType ลงทะเบียนการพึ่งพา และ updateShouldNotify เปรียบเทียบข้อมูลเก่าและใหม่เพื่อพิจารณาว่าวิดเจ็ตที่พึ่งพาจำเป็นต้องสร้างใหม่หรือไม่

การสร้าง InheritedWidget แบบกำหนดเอง

การสร้าง InheritedWidget แบบกำหนดเอง ประกอบด้วยสองขั้นตอน: การกำหนดคลาสที่ขยาย InheritedWidget และการใช้งานเมธอดสแตติก of สำหรับการเข้าถึงจากผู้สืบทอด ข้อมูลถูกส่งผ่านคอนสตรัคเตอร์ และเมธอด updateShouldNotify กำหนดว่าเมื่อใดวิดเจ็ตที่พึ่งพาควรถูกสร้างใหม่

ขั้นตอนที่ 1: กำหนดคลาส InheritedWidget

คลาสต้องขยาย InheritedWidget และรับข้อมูลผ่านคอนสตรัคเตอร์ที่มีพารามิเตอร์ child ที่จำเป็น ข้อมูลสามารถเป็นชนิดใดก็ได้: พรีมิทีฟ, ออบเจ็กต์, ฟังก์ชัน กฎหลักคือข้อมูลต้องไม่เปลี่ยนสภาพ (immutable) เพื่อให้สามารถเปรียบเทียบค่าเก่าและใหม่ได้อย่างน่าเชื่อถือ

ขั้นตอนที่ 2: เมธอดสแตติก of

เมธอดสแตติก of รับ BuildContext และคืนค่าข้อมูล InheritedWidget ภายใน มันเรียก dependOnInheritedWidgetOfExactType ซึ่งค้นหา InheritedWidget ที่ใกล้ที่สุดของชนิดที่ระบุในทรี ถ้าไม่พบ InheritedWidget เมธอดจะโยนข้อยกเว้นหรือคืนค่าเริ่มต้นขึ้นอยู่กับการใช้งาน

ขั้นตอนที่ 3: การใช้งานในวิดเจ็ต

เพื่อเข้าถึงข้อมูล วิดเจ็ตเรียก MyWidget.of(context) ภายในเมธอด build Flutter จะสมัครรับการอัปเดตให้กับวิดเจ็ตโดยอัตโนมัติ ถ้าข้อมูลเปลี่ยนแปลง วิดเจ็ตจะถูกสร้างใหม่ในเฟรมถัดไป ซึ่งช่วยให้โค้ดสะอาดและเป็น declarative โดยไม่มีพารามิเตอร์ที่ไม่จำเป็น

dart
class UserPreferences extends InheritedWidget {
  final String languageCode;
  final bool darkMode;

  const UserPreferences({
    required this.languageCode,
    required this.darkMode,
    required Widget child,
  }) : super(child: child);

  static UserPreferences of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<UserPreferences>()!;
  }

  @override
  bool updateShouldNotify(UserPreferences oldWidget) =>
    oldWidget.languageCode != languageCode || oldWidget.darkMode != darkMode;
}

ในตัวอย่างนี้ UserPreferences เก็บการตั้งค่าผู้ใช้ เมธอด updateShouldNotify เปรียบเทียบแต่ละฟิลด์แยกกัน ซึ่งป้องกันการสร้างใหม่ที่ไม่จำเป็นเมื่อพารามิเตอร์เดียวเปลี่ยนแปลง ใช้แนวทางที่คล้ายกันสำหรับ InheritedWidget แบบกำหนดเองของคุณที่มีหลายฟิลด์

เมธอด updateShouldNotify และการป้องกันการสร้างใหม่ที่ไม่จำเป็น

updateShouldNotify เป็นเมธอดหลักของ InheritedWidget ที่กำหนดว่าวิดเจ็ตที่พึ่งพาจำเป็นต้องได้รับการแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลงข้อมูลหรือไม่ ถ้าเมธอดคืนค่า false วิดเจ็ตที่พึ่งพาจะไม่ถูกสร้างใหม่ แม้ว่า InheritedWidget เองจะได้รับอินสแตนซ์ใหม่ที่มีข้อมูลเดียวกัน นี่เป็นสิ่งสำคัญอย่างยิ่งสำหรับประสิทธิภาพ

การใช้งาน updateShouldNotify ที่ถูกต้อง

เปรียบเทียบเฉพาะฟิลด์ที่ เปลี่ยนแปลงจริง และส่งผลต่อการแสดงผล ถ้า InheritedWidget มี 10 ฟิลด์แต่มีเพียงฟิลด์เดียวที่ส่งผลต่อ UI ให้ตรวจสอบเฉพาะฟิลด์นั้น สำหรับคอลเลกชัน ให้ใช้การเปรียบเทียบเชิงลึกหรือโครงสร้างข้อมูลที่ไม่เปลี่ยนสภาพ อย่าใช้ == สำหรับ List หรือ Map เพราะเปรียบเทียบโดยการอ้างอิง

  • พรีมิทีฟ — ใช้การเปรียบเทียบโดยตรง: oldWidget.value != value.
  • ออบเจ็กต์ที่ไม่เปลี่ยนสภาพ — ใช้ == ที่ถูกแทนที่: oldWidget.data != data (ถ้า data แทนที่ ==).
  • คอลเลกชัน — ใช้ listEquals, mapEquals จาก package:flutter/foundation.dart.

ข้อผิดพลาดในการใช้งาน updateShouldNotify

ข้อผิดพลาดที่พบบ่อยที่สุดคือการคืนค่า true โดยไม่เปรียบเทียบ ซึ่งทำให้วิดเจ็ตที่พึ่งพาทั้งหมดถูกสร้างใหม่ทุกครั้งที่มีการอัปเดตพาเรนต์ แม้ว่าข้อมูลจะไม่เปลี่ยนแปลงก็ตาม ข้อผิดพลาดที่สองคือการคืนค่า false เมื่อข้อมูลเปลี่ยนแปลง ทำให้ UI ล้าสมัย ข้อผิดพลาดที่สามคือการเปรียบเทียบที่ซับซ้อนซึ่งทำงานทุกเฟรมและทำให้ประสิทธิภาพช้าลง

InheritedWidget vs คอลแบ็ก: ควรเลือกอะไร?

InheritedWidget และคอลแบ็ก (การส่งฟังก์ชันผ่านคอนสตรัคเตอร์) แก้ปัญหาที่แตกต่างกัน InheritedWidget เหมาะสำหรับข้อมูลที่จำเป็นโดยวิดเจ็ตจำนวนมากในระดับต่าง ๆ ของทรี คอลแบ็กสะดวกสำหรับการส่งอีเวนต์ทางเดียวจากพาเรนต์ไปยังวิดเจ็ตลูกที่เฉพาะเจาะจงหรือในทางกลับกัน การเลือกขึ้นอยู่กับสถาปัตยกรรมแอปพลิเคชันและความถี่ในการอัปเดต

เมื่อใดควรใช้ InheritedWidget

ใช้ InheritedWidget เมื่อข้อมูลจำเป็นโดย วิดเจ็ตจำนวนมาก ในระดับการซ้อนที่แตกต่างกัน: ธีมแอป, การตั้งค่าผู้ใช้, ข้อมูลอุปกรณ์, ข้อมูลเซสชันปัจจุบัน InheritedWidget มีประสิทธิภาพเป็นพิเศษสำหรับข้อมูล “ทั่วโลก” ที่ไม่ค่อยเปลี่ยนแปลงแต่จำเป็นในส่วนต่าง ๆ ของ UI

เมื่อใดควรใช้คอลแบ็ก

คอลแบ็ก (ฟังก์ชันเรียกกลับ) เหมาะสำหรับการส่งอีเวนต์จากวิดเจ็ตลูกไปยังพาเรนต์: การกดปุ่ม, การเลือกรายการ, การส่งฟอร์ม คอลแบ็กบ่งชี้อย่างชัดเจนว่าวิดเจ็ตลูกสามารถดำเนินการใดได้บ้างและไม่สร้างการพึ่งพาที่ซ่อนอยู่ สำหรับการส่งข้อมูลลงด้านล่างในทรีผ่านระดับจำนวนน้อย การใช้พารามิเตอร์คอนสตรัคเตอร์ก็ง่ายกว่าเช่นกัน

เกณฑ์InheritedWidgetคอลแบ็ก
ทิศทางจากบนลงล่าง (พาเรนต์ → ผู้สืบทอด)จากล่างขึ้นบน (ลูก → พาเรนต์) หรือโดยตรง
ขอบเขตทรีย่อยทั้งหมดวิดเจ็ตเฉพาะ
การสร้างใหม่อัตโนมัติเมื่อข้อมูลเปลี่ยนต้องใช้ setState ด้วยตนเอง
ความซับซ้อนปานกลาง (ต้องใช้คลาส InheritedWidget)ต่ำ (แค่ฟังก์ชัน)

InheritedWidget และไลบรารีการจัดการสถานะ

Provider และ Riverpod เป็นไลบรารีการจัดการสถานะยอดนิยมใน Flutter ที่สร้างบน InheritedWidget พวกมันขยายความสามารถ: เพิ่มการสนับสนุน ChangeNotifier, การล้างข้อมูลอัตโนมัติเมื่อถอดออก, การเริ่มต้นแบบขี้เกียจ และไวยากรณ์ที่เรียบง่ายด้วยジェเนอริก

Provider บนพื้นฐาน InheritedWidget

Provider ใช้ InheritedWidget เพื่อส่งออบเจ็กต์ชนิดใดก็ได้ลงด้านล่างในทรี ChangeNotifierProvider ติดตามการเปลี่ยนแปลงผ่าน ChangeNotifier และเรียก updateShouldNotify เมื่อ notifyListeners ถูกเรียก ซึ่งช่วยให้นักพัฒนาไม่ต้องสร้าง InheritedWidget ด้วยตนเองและใช้งาน updateShouldNotify

การเปรียบเทียบกับ InheritedWidget โดยตรง

InheritedWidget โดยตรงให้การควบคุมมากขึ้นและไม่ต้องการการพึ่งพาภายนอก Provider ให้โครงสร้างพื้นฐานพร้อมใช้: Consumer, Selector, MultiProvider, ProxyProvider การเลือกขึ้นอยู่กับความซับซ้อนของแอปพลิเคชัน สำหรับโปรเจ็กต์ง่าย InheritedWidget โดยตรงก็เพียงพอ สำหรับโปรเจ็กต์ใหญ่ Provider หรือ Riverpod ลดโค้ดเทมเพลต

dart
// InheritedWidget โดยตรง
class UserProvider extends InheritedWidget {
  final UserData userData;
  const UserProvider({required this.userData, required Widget child}) : super(child: child);
  static UserData of(BuildContext context) => context.dependOnInheritedWidgetOfExactType<UserProvider>()!.userData;
  @override
  bool updateShouldNotify(UserProvider old) => old.userData != userData;
}

// เทียบเท่า Provider
return ChangeNotifierProvider<UserData>(
  create: (_) => UserData(),
  child: MyApp(),
);

ทั้งสองแนวทางในตัวอย่างแก้ปัญหาเดียวกัน — การส่ง UserData ลงด้านล่างในทรี Provider ลดปริมาณโค้ดแต่ซ่อนกลไกของ InheritedWidget InheritedWidget โดยตรงให้การควบคุมเต็มที่และความเข้าใจในสิ่งที่เกิดขึ้น ซึ่งสำคัญเป็นพิเศษเมื่อเรียนรู้ Flutter และดีบักปัญหาการสร้างใหม่ที่ซับซ้อน

คำถามที่พบบ่อย

InheritedWidget แตกต่างจากวิดเจ็ตทั่วไปอย่างไร?

InheritedWidget ทำให้ข้อมูลพร้อมใช้งานสำหรับผู้สืบทอดทั้งหมดผ่าน BuildContext ในขณะที่วิดเจ็ตทั่วไปส่งข้อมูลผ่านคอนสตรัคเตอร์เท่านั้น InheritedWidget ยังสมัครรับการอัปเดตข้อมูลให้กับผู้สืบทอดด้วย

วิดเจ็ตที่พึ่งพาถูกสร้างใหม่บ่อยแค่ไหน?

วิดเจ็ตที่พึ่งพาจะถูกสร้างใหม่เมื่อ updateShouldNotify คืนค่า true เท่านั้น ถ้าเมธอดถูกใช้งานอย่างถูกต้อง การสร้างใหม่จะเกิดขึ้นเมื่อข้อมูลเปลี่ยนแปลงจริงเท่านั้น ไม่ใช่ทุกครั้งที่พาเรนต์ถูกสร้างใหม่

สามารถใช้ InheritedWidget หลายตัวในทรีเดียวกันได้หรือไม่?

ได้ คุณสามารถใช้ InheritedWidget จำนวนเท่าใดก็ได้ ในทรีเดียวกัน แต่ละตัวให้ข้อมูลชนิดเฉพาะ และวิดเจ็ตสามารถรับข้อมูลจาก InheritedWidget หลายตัวพร้อมกัน

อะไรคือความแตกต่างระหว่าง dependOnInheritedWidgetOfExactType และ findAncestorWidgetOfExactType?

dependOn สมัครรับการอัปเดตให้วิดเจ็ต — เมื่อข้อมูลเปลี่ยนแปลง วิดเจ็ตจะถูกสร้างใหม่ findAncestor ทำการค้นหาครั้งเดียวโดยไม่สมัครรับ และวิดเจ็ตจะไม่ทราบเกี่ยวกับการเปลี่ยนแปลงข้อมูล

InheritedWidget เหมาะสำหรับการจัดการสถานะที่ซับซ้อนหรือไม่?

สำหรับ สถานะง่าย (ธีม, การตั้งค่า) InheritedWidget ก็เพียงพอ สำหรับสถานะซับซ้อนที่มีตรรกะทางธุรกิจ ใช้ Provider, Riverpod หรือ BLoC — สิ่งเหล่านี้สร้างบน InheritedWidget และเพิ่มโครงสร้างพื้นฐานที่จำเป็น

สรุป

  • InheritedWidget เป็นวิดเจ็ตพิเศษของ Flutter สำหรับส่งข้อมูลลงด้านล่างในทรีพร้อมการสมัครรับการอัปเดตอัตโนมัติ
  • กลไกการทำงาน ขึ้นอยู่กับ Element Tree: InheritedElement ลงทะเบียนองค์ประกอบที่พึ่งพาและแจ้งพวกมันเกี่ยวกับการเปลี่ยนแปลง
  • updateShouldNotify — เมธอดหลักสำหรับป้องกันการสร้างใหม่ที่ไม่จำเป็นของวิดเจ็ตที่พึ่งพา
  • InheritedWidget ในตัว: Theme, MediaQuery, Localizations, Directionality, DefaultTextStyle
  • การสร้างแบบกำหนดเอง รวมถึงการสืบทอดคลาส การส่งข้อมูลผ่านคอนสตรัคเตอร์ และเมธอดสแตติก of
  • Provider และ Riverpod สร้างบน InheritedWidget และเพิ่ม ChangeNotifier, Consumer, Selector และไวยากรณ์ที่เรียบง่าย
  • InheritedWidget แก้ปัญหา prop drilling และเป็นรากฐานของการจัดการสถานะแบบรีแอกทีฟใน Flutter

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม