Flutter EP.5 จัดการ State ใน flutter ด้วย Provider

6 Jun 2020,
Share: 
Cover image

สวัสดีครับ ใน EP.4 เราได้เรียนรู้ Project structure file flutter กันไปแล้วนะครับ ในบทความนี้เราจะมาเรียนรู้การจัดการ State ใน Flutter ด้วย Provider กันครับ

โดยปกติเวลาที่เราจะเปลี่ยนข้อมูลใน State เพื่อไป Update UI เราสามารถทําได้ด้วยการใช้คําสั่ง setState() ได้ตามตัวอย่างนี้ (อ่านเพิ่มเติมได้จาก EP.3)

setState((){
   title = "New title";
});

เมื่อมีการ setSate() จะทําให้ Widget นั้น build Widget ใหม่ทั้งหมด ทําให้ประสิทธิภาพของแอปไม่ดีอย่างที่ควรจะเป็น และในความเป็นจริง Application ของเราไม่ได้มีแค่ Widget เดียว และในแต่ละ Widget มีการใช้งาน State ร่วมกัน จึงต้องมี State Management เข้ามาช่วยเพื่อให้เราจัดการ State ได้ง่ายขึ้น

State Management มีอยู่ด้วยกันหลายตัวเช่น Provider, Redux, BLoC/Rx, MobX สําหรับบทความนี้เราจะมาเรียนรู้การจัดการ State ด้วย Provider กันครับ

แนวคิดของการจัดการ State คือจะสร้าง State เก็บไว้ที่เดียว และเมื่อ Widget ไหนต้องการใช้งานก็จะไปหยิบมาใช้ ตัวอย่างตามรูปด้านล่างครับ

Image

การใช้งาน Provider มีดังนี้

Setp1: เพิ่ม Dependencies

เพิ่ม dependencies ของ provider ใน pubspec.yaml

dependencies:
  flutter:
    sdk: flutter

  ...
  provider: ^4.0.0

Step2: สร้าง Model Provider

การสร้าง Model Provider เพื่อเก็บข้อมูลต่างๆที่เราต้องการ และ Method การทํางานต่างๆ รวมไปถึงการ Update Widget เมื่อข้อมูล State เปลี่ยนแปลง ซึ่งการสร้าง Model Provider คือให้เรา สร้าง Class โดย extends class ChangeNotifier และเมื่อต้องการ Update UI เราก็จะเรียก Function notifyListener() ในบทความนี้เราจะยกตัวอย่างสร้างขึ้นมา 2 Model Provider ดังนี้

class CounterProvider extends ChangeNotifier {
  int counter;
  CounterProvider({this.counter = 0});

  increment() {
    counter++;
    notifyListeners();
  }
}

class CounterProvider2 extends ChangeNotifier {
  int counter;
  CounterProvider({this.counter = 0});

  increment(int number) {
    counter += number;
    notifyListeners();
  }
}

Step3: ใช้ Provider ใน Widget

ก่อนอื่น import provider เข้ามาก่อน

import 'package:provider/provider.dart';

เราจะใช้ ChangeNotifierProvider กับ Widget ที่ต้องการจะใช้งาน State ครับ

ในตัวอย่างนี้เราจะใส่ไว้ใน Widget บนสุดเลย ตามนี้ครับ

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.teal,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MultiProvider(
        providers: [
          ChangeNotifierProvider(create: (_) => CounterProvider(counter: 0)),
          ChangeNotifierProvider(create: (_) => CounterProvider2(counter: 0))
        ],
        child: MyHomePage(title: "My Home")
      ),
    );
  }
}

หรือกรณีที่เราจะใช้งานแค่ 1 Provider ก็สามารถทําแบบนี้ได้ครับ

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.teal,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: ChangeNotifierProvider(
        create: (_) => CounterProvider(counter: 0),
        child: MyHomePage(title: "My Home"),
      ),
    );
  }
}

เมื่อเรากําหนด ChangeNotifierProvider แล้ว ใน Widget MyHomePage ของเราจะต้อง get Object ของ Provider ที่เราต้องการโดยใช้คําสั่ง Provider.of() ตามตัวอย่างนี้

...

CounterProvider counterProvider = Provider.of<CounterProvider>(context);
CounterProvider2 counterProvider2 = Provider.of<CounterProvider2>(context);

...

หลังจากนั้นเมื่อเราต้องการจะนําข้อมูล State มาแสดงผลก็สามารถทําได้โดยใช้ Consumer ตามตัวอย่างนี้

...

Consumer<CounterProvider>(
  builder: (context, data, child) => Text(
    '${data.counter}',
    style: Theme.of(context).textTheme.headline4,
  ),
),

...

แต่ในบางครั้งเราต้องการใช้งานหลาย Provider ก็สามารถทําได้ครับโดยใช้ Consumer2, Consumer3, Consumer4, Consumer(N) โดยใช้งานได้สูงสุด 6 Provider ครับ ตามตัวอย่างนี้

...

Consumer2<CounterProvider, CounterProvider2>(
  builder: (context, data, data2, child) => Text(
    '${data.counter} --> ${data2.counter}',
    style: Theme.of(context).textTheme.headline4,
  ),
),

...

กรณีที่ต้องการจะ Update State เราก็ใช้งานผ่าน Object Provider ที่เรา get มาตอนต้นครับตามตัวอย่างนี้

...

floatingActionButton: FloatingActionButton(
  onPressed: () {
    counterProvider.increment();
    counterProvider2.increment(2);
    },
  tooltip: 'Increment',
  child: Icon(Icons.add),
),

...

มาดูตัวอย่างเต็มๆกันครับประมาณนี้

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    CounterProvider counterProvider = Provider.of<CounterProvider>(context);
    CounterProvider2 counterProvider2 = Provider.of<CounterProvider2>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Consumer2<CounterProvider, CounterProvider2>(
              builder: (context, data, data2, child) => Text(
                '${data.counter} --> ${data2.counter}',
                style: Theme.of(context).textTheme.headline4,
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          counterProvider.increment();
          counterProvider2.increment(2);
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

การใช้งานก็ประมาณนี้ครับ

แล้วพบกันในบทความหน้านะครับ ขอบคุณครับ

Suggestion blogs

ติดตั้ง node.js และ npm

Imagenode.js คืออะไร?node.js คือการเขียนโปรแกรมด้วยภาษา javascript บนฝั่ง Server จริงๆแล้ว node.js จะรวม environment ต่างๆ ที่ทำขึ้นเพื่อให้เราเขียน JavaScript เอาไว้ที่ฝั่ง server node.js นั้นขึ้นชื่อในเรื่องความเร็วของการประมวลผล จึงทำให้ application ที่เขียนด้วย Node.js นั้นมีจำนวนเพิ่มขึ้นอย่างรวดเร็ว

Vue.js เริ่มต้น ตอน9 (List Rendering v-for)

ในบทความนี้เราจะมาเรียนรู้การวนลูปแสดงข้อมูลในลักษณะ List ซึ่ง Vue ก็มีเครื่องมือมาให้เราใช้งานได้อย่างง่ายดาย ก็คือ v-for มันสามารถใช้งานได้ทั้ง Array และ Object มาดูตัวอย่างแรกกันเลย

Singleton pattern

Singleton pattern เป็น Design pattern ที่ใช้จํากัดจํานวนของอ็อบเจกต์ที่ถูกสร้างในขณะที่โปรแกรมทํางาน จะมีประโยชน์ในกรณีที่ระบบงานต้องการบังคับให้มีแค่อ็อบเจกต์เดียวเพื่อไม่ให้เกิดการซํ้าซ้อนกันเช่น Class ที่ใช้ในการควบคุม Hardware 1 ตัว ในการควบคุม Hardware 1 ตัวถ้าสร้างอ็อบเจกต์เพื่อควบคุมขึ้นมาหลายตัวอาจจะทําให้เกิดปัญหาในการควบคุม Hardware ได้


Copyright © 2019 - 2025 thiti.dev |  v1.58.0 |  Privacy policy | 

Build with ❤️ and Astro.

Github profile   Linkedin profile   Instagram   X profile   Nostr   Youtube channel   Telegram   Email contact   วงแหวนเว็บ