メインコンテンツへ移動

เนื้อหาภาษาไทย / タイ語のコンテンツ

システムガイド 内容確認済み

การใช้ InheritedWidget เพื่อส่งข้อมูลลงไปใน Widget Tree

บทความนี้แนะนำ `InheritedWidget` ซึ่งเป็น Widget พิเศษใน Flutter ที่ช่วยให้ Widget ลูกหลานสามารถเข้าถึงข้อมูลจาก Widget ต้นทางได้โดยตรง ลดความซับซ้อนของการส่งข้...

การใช้ InheritedWidget เพื่อส่งข้อมูลลงไปใน Widget Tree

ในบทความก่อนหน้า เราได้เรียนรู้เกี่ยวกับการสร้าง Custom Widget ที่มี State และการจัดการ State ด้วย StatefulWidget ในบทความนี้ เราจะมาเรียนรู้วิธีการส่งข้อมูลจาก Widget ต้นทางไปยัง Widget ลูกหลานที่อยู่ใน Widget Tree โดยไม่ต้องทำการส่งผ่านข้อมูล (Prop Drilling) ผ่าน Widget แต่ละตัว ซึ่งทำได้ด้วย InheritedWidget

InheritedWidget คืออะไร?

InheritedWidget เป็น Widget พิเศษใน Flutter ที่ช่วยให้ Widget ลูกหลานสามารถเข้าถึงข้อมูลที่ถูกจัดเก็บไว้ใน InheritedWidget ได้โดยตรง โดยไม่ต้องส่งผ่านข้อมูลผ่านทาง constructor ของแต่ละ Widget (Prop Drilling) ทำให้โค้ดมีความสะอาด อ่านง่าย และบำรุงรักษาได้ง่ายขึ้น

แนวคิดเบื้องหลัง InheritedWidget คือการสร้าง "ท่อ" หรือ "ช่องทาง" ให้ Widget ลูกหลานสามารถ "แอบมอง" และดึงข้อมูลจาก Widget ต้นทางได้เมื่อต้องการ โดย Flutter จะทำการแจ้งเตือน (notify) Widget ลูกหลานที่ใช้งานข้อมูลนั้นเมื่อข้อมูลมีการเปลี่ยนแปลง ทำให้ UI สามารถอัปเดตได้อย่างถูกต้อง

โครงสร้างของ InheritedWidget

ในการสร้าง InheritedWidget เราจะต้องสร้าง class ที่ extends InheritedWidget และ override method updateShouldNotify ซึ่งเป็นตัวกำหนดว่า Widget ลูกหลานควรถูก rebuild หรือไม่เมื่อข้อมูลใน InheritedWidget มีการเปลี่ยนแปลง

class MyInheritedWidget extends InheritedWidget {
  const MyInheritedWidget({
    Key? key,
    required this.data,
    required Widget child,
  }) : super(key: key, child: child);

  final String data;

  @override
  bool updateShouldNotify(MyInheritedWidget oldWidget) {
    return data != oldWidget.data; // rebuild ถ้า data เปลี่ยน
  }

  // Helper method เพื่อให้ Widget ลูกหลานเข้าถึงข้อมูลได้ง่าย
  static MyInheritedWidget? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
  }
}

คำอธิบาย Code:

  • MyInheritedWidget: คือ class ที่ extends InheritedWidget
  • data: คือข้อมูลที่เราต้องการส่งต่อให้กับ Widget ลูกหลาน
  • child: คือ Widget ที่ InheritedWidget ครอบอยู่ ซึ่ง Widget ลูกหลานจะอยู่ใน subtree ของ child นี้
  • updateShouldNotify: เป็น method ที่เรา override เพื่อกำหนดว่า Widget ลูกหลานควรถูก rebuild หรือไม่ เมื่อ data เปลี่ยนแปลง
  • of(BuildContext context): เป็น helper method ที่ช่วยให้ Widget ลูกหลานสามารถเข้าถึง MyInheritedWidget ได้ง่ายขึ้น โดยใช้ BuildContext.dependOnInheritedWidgetOfExactType

การใช้งาน InheritedWidget

ขั้นตอนการใช้งาน InheritedWidget มีดังนี้:

  1. สร้าง InheritedWidget class (ตามตัวอย่างด้านบน)
  2. วาง InheritedWidget ไว้เหนือ Widget Tree ที่เราต้องการให้ Widget ลูกหลานเข้าถึงข้อมูลได้
  3. ใช้ BuildContext.dependOnInheritedWidgetOfExactType หรือ helper method ที่เราสร้างขึ้น (เช่น MyInheritedWidget.of(context)) ใน Widget ลูกหลานเพื่อดึงข้อมูล

ตัวอย่าง:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'InheritedWidget Example',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _data = 'Initial Data';

  void _updateData() {
    setState(() {
      _data = 'Updated Data';
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('InheritedWidget Example'),
      ),
      body: MyInheritedWidget(
        data: _data,
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('Data from InheritedWidget:'),
              MyDataWidget(),
              ElevatedButton(
                onPressed: _updateData,
                child: Text('Update Data'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class MyInheritedWidget extends InheritedWidget {
  const MyInheritedWidget({
    Key? key,
    required this.data,
    required Widget child,
  }) : super(key: key, child: child);

  final String data;

  @override
  bool updateShouldNotify(MyInheritedWidget oldWidget) {
    return data != oldWidget.data;
  }

  static MyInheritedWidget? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
  }
}

class MyDataWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final inheritedWidget = MyInheritedWidget.of(context);
    return Text(
      inheritedWidget?.data ?? 'No Data',
      style: TextStyle(fontSize: 20),
    );
  }
}

คำอธิบาย Code:

  • MyHomePage: เป็น StatefulWidget ที่มี State คือ _data ซึ่งเป็น String
  • MyInheritedWidget: ครอบ Center Widget ไว้ ทำให้ MyDataWidget สามารถเข้าถึงข้อมูล _data ได้
  • MyDataWidget: ใช้ MyInheritedWidget.of(context) เพื่อดึงข้อมูล _data จาก MyInheritedWidget
  • เมื่อกดปุ่ม "Update Data" ค่า _data ใน MyHomePage จะถูกอัปเดต และ MyDataWidget จะถูก rebuild โดยอัตโนมัติ เนื่องจาก updateShouldNotify ใน MyInheritedWidget คืนค่า true

ข้อดีและข้อเสียของ InheritedWidget

ข้อดี:

  • ลดความซับซ้อนของโค้ด โดยไม่ต้องส่งผ่านข้อมูลผ่าน Prop Drilling
  • ทำให้ Widget สามารถเข้าถึงข้อมูลจาก Widget ต้นทางได้โดยตรง
  • Flutter จะทำการ rebuild Widget ลูกหลานที่ใช้งานข้อมูลนั้นเมื่อข้อมูลมีการเปลี่ยนแปลงโดยอัตโนมัติ

ข้อเสีย:

  • อาจทำให้เกิดความสับสนในการ debug หากไม่เข้าใจการทำงานของ InheritedWidget
  • การ rebuild Widget ลูกหลานที่ไม่จำเป็นอาจทำให้เกิด performance issue ได้ หาก updateShouldNotify ไม่ได้ถูก implement อย่างถูกต้อง

InheritedWidget กับ State Management Solutions

InheritedWidget เป็นพื้นฐานของ State Management Solutions หลายตัวใน Flutter เช่น Provider, Riverpod, และ BLoC โดย libraries เหล่านี้จะช่วยให้การจัดการ State ในแอปพลิเคชันขนาดใหญ่มีความซับซ้อนน้อยลง และมีประสิทธิภาพมากขึ้น

สรุป

InheritedWidget เป็นเครื่องมือที่มีประโยชน์ในการส่งข้อมูลลงไปใน Widget Tree โดยไม่ต้อง Prop Drilling ทำให้โค้ดมีความสะอาด อ่านง่าย และบำรุงรักษาได้ง่ายขึ้น อย่างไรก็ตาม ควรระมัดระวังในการใช้งานเพื่อให้มั่นใจว่า updateShouldNotify ถูก implement อย่างถูกต้อง และไม่ทำให้เกิด performance issue ในบทความถัดไป เราจะเรียนรู้เกี่ยวกับการจัดการ State อย่างมีประสิทธิภาพด้วย Provider ซึ่งเป็น State Management Solution ที่ได้รับความนิยมใน Flutter

Office.in.th Custom Service

この構成をもとにシステムを開発・カスタマイズしたいですか?

Office.in.th は、エンタープライズ Web アプリケーション、API 連携、官民の業務管理システムの設計・開発を承り、長期的なサポートも提供します。

ソフトウェア開発サービスを見る