Cover image

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

6 Jun 2020

Share to:

สวัสดีครับ ใน 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

วิธีออกแบบระบบ โซล่าเซลล์

ในบทความนี้เป็นเรื่องเกี่ยวกับการออกแบบและคํานวณระบบโซล่าเซลล์ ซึ่งจะหาว่าถ้าเราใช้อุปกณ์ไฟฟ้าเท่านี้เราจะใช้โซล่าเซลล์ เท่าไร แบตเตอรรี่เท่าไร

Go EP.6 Go Channel

สวัสดีครับ ในบทความนี้ก็เป็น EP.6 แล้วนะครับ โดยเนื้อหาจะเป็นเรื่องเกี่ยวกับ Go Channel ซึ่งเป็นเรื่องที่ต่อเนื่องจาก Go EP.5 Go Routine ครับสําหรับท่านใดที่ยังไม่ได้อ่าน EP.5 ท่านสามารถกลับไปอ่านก่อนได้นะครับที่นี่ Go EP.5 Go Routineมาเริ่มเรียนรู้ไปด้วยกันตามหัวข้อด้านล่างเลยครับ

เริ่มต้นใช้งาน IPFS ด้วย Docker

สวัสดีครับ ในบทความนี้ผมจะอธิบายการใช้งาน IPFS ด้วย Docker ซึ่งการใช้งาน IPFS ด้วย Docker นั้นเป็นแนวทางนึงในการใช้งาน IPFS สําหรับใครที่อยากจะติดตั้งบนเครื่องก็สามารถอ่านเพิ่มเติมได้จาก Document ของ IPFS ได้เลยครับ แต่โดยส่วนตัวของผมนั้น ผมชอบที่จะใช้ผ่าน Docker เนื่องจากไม่ต้องติดตั้ง IPFS บนเครื่องของเรา ถ้าใครยังไม่รู้จัก Docker สามารถไปอ่านบนความเก่าๆได้ครับที่นี่ https://thiti.dev/tags/docker


Copyright © 2024 thiti.dev |  v1.16.0 |  Privacy policy |  status | 

            วงแหวนเว็บ