본문으로 건너뛰기

เนื้อหาภาษาไทย / 태국어 콘텐츠

시스템 가이드 검수 완료된 콘텐츠

จัดการ State อย่างมีประสิทธิภาพด้วย Provider

บทความนี้แนะนำ Provider ซึ่งเป็น State Management Solution ที่ได้รับความนิยมใน Flutter เพื่อจัดการ State อย่างมีประสิทธิภาพในแอปพลิเคชันขนาดใหญ่ โดย Provider ช่...

จัดการ State อย่างมีประสิทธิภาพด้วย Provider ใน Flutter

ในบทความที่แล้ว เราได้เรียนรู้เกี่ยวกับการสร้าง Layout ที่ซับซ้อนด้วย Custom Layouts ใน Flutter ซึ่งช่วยให้เราควบคุมการจัดเรียง Widget ได้อย่างละเอียดมากยิ่งขึ้น แต่เมื่อแอปพลิเคชันของเรามีขนาดใหญ่ขึ้น การจัดการ State (สถานะของข้อมูล) ก็กลายเป็นเรื่องที่ท้าทายมากยิ่งขึ้นเช่นกัน ในบทความนี้ เราจะมาเรียนรู้วิธีการจัดการ State อย่างมีประสิทธิภาพด้วย Provider ซึ่งเป็นหนึ่งใน State Management Solutions ที่ได้รับความนิยมอย่างมากใน Flutter

Provider ช่วยให้เราสามารถเข้าถึง State ได้จากทุกส่วนของ Widget Tree โดยไม่ต้องส่งผ่านข้อมูล (Prop Drilling) ให้ยุ่งยาก และยังช่วยลดความซับซ้อนในการจัดการ State ในแอปพลิเคชันขนาดใหญ่ได้อีกด้วย

ทำไมต้อง State Management?

ลองนึกภาพแอปพลิเคชันที่มีข้อมูลที่ต้องแสดงผลในหลายๆ หน้าจอ และข้อมูลนั้นมีการเปลี่ยนแปลงอยู่ตลอดเวลา หากเราไม่ใช้ State Management Solution ที่ดี เราจะต้องส่งผ่านข้อมูลจาก Widget หนึ่งไปยังอีก Widget หนึ่ง ซึ่งอาจทำให้โค้ดของเราซับซ้อนและยากต่อการบำรุงรักษา

State Management Solution ช่วยให้เราสามารถจัดการ State ได้อย่างเป็นระบบ ทำให้โค้ดของเราอ่านง่าย เข้าใจง่าย และบำรุงรักษาง่ายขึ้น

Provider คืออะไร?

Provider คือ Package ที่ช่วยให้เราสามารถจัดการ State ใน Flutter ได้อย่างง่ายดาย โดย Provider จะทำหน้าที่เป็น "ผู้ให้บริการ" ที่คอยจัดหา State ให้กับ Widget ที่ต้องการใช้งาน

Provider มีหลายประเภท แต่ในบทความนี้ เราจะเน้นที่ 3 ประเภทหลักๆ คือ:

  • ChangeNotifierProvider: สำหรับจัดการ State ที่มีการเปลี่ยนแปลงและแจ้งเตือน Widget ที่ใช้งานอยู่
  • StreamProvider: สำหรับจัดการ State ที่เป็น Stream (ข้อมูลที่เปลี่ยนแปลงตลอดเวลา)
  • MultiProvider: สำหรับรวม Provider หลายๆ ตัวเข้าด้วยกัน

ChangeNotifierProvider

ChangeNotifierProvider เป็น Provider ที่ใช้งานง่ายและเหมาะสำหรับจัดการ State ที่มีการเปลี่ยนแปลงอยู่ตลอดเวลา เช่น ข้อมูลผู้ใช้, จำนวนสินค้าในตะกร้า, หรือสถานะการโหลดข้อมูล

เพื่อให้เข้าใจการทำงานของ ChangeNotifierProvider มากขึ้น เราจะมาสร้างตัวอย่างง่ายๆ โดยสร้าง Counter App ที่มีปุ่มสำหรับเพิ่มและลดจำนวน

1. สร้าง Class ที่ extends ChangeNotifier:

import 'package:flutter/material.dart';

class Counter extends ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners(); // แจ้งเตือน Widget ที่ใช้งานว่า State มีการเปลี่ยนแปลง
  }

  void decrement() {
    _count--;
    notifyListeners(); // แจ้งเตือน Widget ที่ใช้งานว่า State มีการเปลี่ยนแปลง
  }
}

ใน Class Counter เรามี:

  • _count: ตัวแปรสำหรับเก็บค่า Counter
  • count: Getter method สำหรับเข้าถึงค่า _count
  • increment() และ decrement(): Method สำหรับเพิ่มและลดค่า _count และเรียก notifyListeners() เพื่อแจ้งเตือน Widget ที่ใช้งานว่า State มีการเปลี่ยนแปลง

2. ห่อ Widget ด้วย ChangeNotifierProvider:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => Counter(),
      child: MyApp(),
    ),
  );
}

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

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter App'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: &ltWidget&gt[
            Text(
              'You have pushed the button this many times:',
            ),
            Consumer&ltCounter&gt( // ใช้ Consumer เพื่อเข้าถึง State
              builder: (context, counter, child) {
                return Text(
                  '${counter.count}',
                  style: Theme.of(context).textTheme.headline4,
                );
              },
            ),
          ],
        ),
      ),
      floatingActionButton: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: &ltWidget&gt[
          FloatingActionButton(
            onPressed: () {
              Provider.of&ltCounter&gt(context, listen: false).decrement(); // ใช้ Provider.of เพื่อเรียก method decrement
            },
            tooltip: 'Decrement',
            child: Icon(Icons.remove),
          ),
          SizedBox(width: 10),
          FloatingActionButton(
            onPressed: () {
              Provider.of&ltCounter&gt(context, listen: false).increment(); // ใช้ Provider.of เพื่อเรียก method increment
            },
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
        ],
      ),
    );
  }
}

ใน Code นี้ เราใช้:

  • ChangeNotifierProvider ใน main() เพื่อสร้าง Instance ของ Counter และทำให้ Instance นี้พร้อมใช้งานสำหรับ Widget ทั้งหมดภายใต้ MyApp
  • Consumer&ltCounter&gt ใน MyHomePage เพื่อเข้าถึงค่า count และแสดงผลบนหน้าจอ เมื่อค่า count เปลี่ยนแปลง Consumer จะ Rebuild Widget ที่อยู่ภายในโดยอัตโนมัติ
  • Provider.of&ltCounter&gt(context, listen: false).increment() และ Provider.of&ltCounter&gt(context, listen: false).decrement() ใน FloatingActionButton เพื่อเรียก Method increment() และ decrement() ของ Counter (listen: false หมายถึงเราไม่ต้องการให้ Widget นี้ Rebuild เมื่อ State เปลี่ยนแปลง)

StreamProvider

StreamProvider เหมาะสำหรับจัดการ State ที่เป็น Stream เช่น ข้อมูลจาก Firebase Realtime Database หรือข้อมูลจาก Sensor ต่างๆ

สมมติว่าเรามี Stream ที่ปล่อยตัวเลขสุ่มออกมา เราสามารถใช้ StreamProvider เพื่อแสดงผลตัวเลขสุ่มบนหน้าจอได้ดังนี้:

import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

Stream&ltint&gt randomNumberStream() {
  return Stream.periodic(Duration(seconds: 1), (count) {
    return Random().nextInt(100); // สร้างเลขสุ่มระหว่าง 0-99
  });
}

void main() {
  runApp(
    StreamProvider&ltint&gt(
      create: (context) => randomNumberStream(),
      initialData: 0, // ค่าเริ่มต้นของ Stream
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Random Number App',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Random Number App'),
        ),
        body: Center(
          child: Consumer&ltint&gt(
            builder: (context, randomNumber, child) {
              return Text(
                'Random Number: $randomNumber',
                style: TextStyle(fontSize: 24),
              );
            },
          ),
        ),
      ),
    );
  }
}

ใน Code นี้ เราใช้:

  • randomNumberStream(): Function ที่สร้าง Stream ที่ปล่อยตัวเลขสุ่มออกมาทุกๆ 1 วินาที
  • StreamProvider&ltint&gt ใน main() เพื่อสร้าง Provider ที่คอยรับข้อมูลจาก randomNumberStream() และทำให้ข้อมูลนี้พร้อมใช้งานสำหรับ Widget ทั้งหมดภายใต้ MyApp
  • Consumer&ltint&gt ใน MyApp เพื่อเข้าถึงตัวเลขสุ่มล่าสุดและแสดงผลบนหน้าจอ

MultiProvider

MultiProvider ช่วยให้เราสามารถรวม Provider หลายๆ ตัวเข้าด้วยกันได้ ซึ่งมีประโยชน์อย่างมากเมื่อแอปพลิเคชันของเรามี State ที่ต้องจัดการหลายส่วน

สมมติว่าเรามี Provider สำหรับจัดการข้อมูลผู้ใช้ (UserProvider) และ Provider สำหรับจัดการ Theme ของแอปพลิเคชัน (ThemeProvider) เราสามารถใช้ MultiProvider เพื่อรวม Provider ทั้งสองเข้าด้วยกันได้ดังนี้:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class User {
  final String name;
  final String email;

  User({required this.name, required this.email});
}

class UserProvider extends ChangeNotifier {
  User _user = User(name: 'Guest', email: 'guest@example.com');

  User get user => _user;

  void updateUser(String name, String email) {
    _user = User(name: name, email: email);
    notifyListeners();
  }
}

class ThemeProvider extends ChangeNotifier {
  ThemeMode _themeMode = ThemeMode.light;

  ThemeMode get themeMode => _themeMode;

  void toggleTheme() {
    _themeMode = _themeMode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
    notifyListeners();
  }
}

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => UserProvider()),
        ChangeNotifierProvider(create: (context) => ThemeProvider()),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final themeProvider = Provider.of&ltThemeProvider&gt(context);
    return MaterialApp(
      title: 'MultiProvider Example',
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      themeMode: themeProvider.themeMode,
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final userProvider = Provider.of&ltUserProvider&gt(context);
    final themeProvider = Provider.of&ltThemeProvider&gt(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('MultiProvider Example'),
        actions: [
          IconButton(
            icon: Icon(themeProvider.themeMode == ThemeMode.light ? Icons.dark_mode : Icons.light_mode),
            onPressed: () {
              themeProvider.toggleTheme();
            },
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: &ltWidget&gt[
            Text('User Name: ${userProvider.user.name}'),
            Text('User Email: ${userProvider.user.email}'),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                userProvider.updateUser('John Doe', 'john.doe@example.com');
              },
              child: Text('Update User'),
            ),
          ],
        ),
      ),
    );
  }
}

ใน Code นี้ เราใช้:

  • UserProvider: Provider สำหรับจัดการข้อมูลผู้ใช้
  • ThemeProvider: Provider สำหรับจัดการ Theme ของแอปพลิเคชัน
  • MultiProvider: เพื่อรวม UserProvider และ ThemeProvider เข้าด้วยกัน

สรุป

Provider เป็นเครื่องมือที่มีประสิทธิภาพในการจัดการ State ใน Flutter ช่วยให้เราสามารถเข้าถึง State ได้จากทุกส่วนของ Widget Tree และลดความซับซ้อนในการจัดการ State ในแอปพลิเคชันขนาดใหญ่ ในบทความนี้ เราได้เรียนรู้เกี่ยวกับ ChangeNotifierProvider, StreamProvider, และ MultiProvider ซึ่งเป็น Provider ประเภทหลักๆ ที่เราสามารถนำไปประยุกต์ใช้ในการพัฒนาแอปพลิเคชัน Flutter ได้

ในบทความถัดไป เราจะมาเรียนรู้เกี่ยวกับการใช้งาน FutureBuilder และ StreamBuilder อย่างละเอียด ซึ่งเป็น Widget ที่ช่วยให้เราจัดการกับ Asynchronous Operations ได้อย่างง่ายดาย

Office.in.th Custom Service

이 구조를 바탕으로 시스템을 개발하거나 맞춤 변경하고 싶으신가요?

Office.in.th는 엔터프라이즈 웹 애플리케이션, API 연동, 공공/민간 업무 관리 시스템을 설계·개발하며 장기 지원을 제공합니다.

소프트웨어 개발 서비스 보기