- vừa được xem lúc

[Flutter] Tìm hiểu về state management với Provider

0 0 67

Người đăng: Nguyễn Thanh Tuấn

Theo Viblo Asia

Trong React và Flutter thì vấn đề khó nhất chính là quản lý state, mỗi khi state thay đổi, một số thành phần trên giao diện sẽ được render lại. Điều này quyết định đến hiệu năng của ứng dụng. Trong bài viết lần này, chúng ta sẽ cùng nhau tìm hiểu về một thư viện quản lý state cho Flutter, đó là Provider.

Thư viện này cung cấp rất nhiều thành phần, tuy nhiên để đơn giản nhất, chúng ta sẽ chỉ tìm hiểu 3 thành phần sau đây

  • Provider
  • ChangeNotifierProvider
  • Consumer

Setup

Trước hết, chúng ta sẽ tạo 1 project nhỏ và có UI như sau

class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('My App')), backgroundColor: Colors.grey, body: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Container( padding: const EdgeInsets.all(20), color: Colors.green[200], child: RaisedButton( child: Text('Do something'), onPressed: () {}, ), ), Container( padding: const EdgeInsets.all(35), color: Colors.blue[200], child: Text('Show something'), ), ], ), ), ); }
}

Chúng ta sẽ có 2 thành phần của widget này là RaisedButtonText.

Add thư viện vào project

dependencies: provider: ^4.0.4

Chắc chắn chúng ta cần chạy lệnh sau nhé, hoặc sử dụng IDE để get

flutter pub get

Provider

Provider là một provider widget đơn giản nhất trong tất cả các provider mà thư viện cung cấp. Hiểu đơn giản là widget này sẽ cung cấp một object mà chúng ta có thể sử dụng chúng ở bất kỳ đâu trong cây widget được bao bởi Provider.

Giả sử với ví dụ trên, chúng ta có một object như sau

class MyModel { String text = "Hello"; void doSomething() { text = "World"; }
}

Chúng ta sẽ wrap widget trong ví dụ bởi một Provider. Để lấy được object này trong các widget con, chúng ta cần sử dụng Consumer như sau

class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Provider<MyModel>( create: (context) => MyModel(), child: MaterialApp( home: Scaffold( appBar: AppBar(title: Text('My App')), backgroundColor: Colors.grey, body: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Container( padding: const EdgeInsets.all(20), color: Colors.green[200], child: Consumer<MyModel>( builder: (context, mymodel, child) { return RaisedButton( child: Text('Do something'), onPressed: () { mymodel.doSomething(); }, ); }, ), ), Container( padding: const EdgeInsets.all(35), color: Colors.blue[200], child: Consumer<MyModel>( builder: (context, mymodel, child) { return Text(mymodel.text); }, ), ), ], ), ), ), ); }
}

Vậy khi chúng ta press vào button thì text trên có Text có thay đổi không? Câu trả lời là không bởi vì Provider chỉ đơn giản cung cấp một object là mymodel cho các widget con của nó, chứ ko lắng nghe bất cứ sự thay đổi nào của mymodel.

ChangeNotifierProvider

Không giống như Provider, ChangeNotifierProvider sẽ lắng nghe sự thay đổi của object mà nó cung cấp. Khi object có sự thay đổi, widget được return từ builder function của Consumer sẽ được render lại.

Model của chúng ta cần sử dụng ChangeNotifie (mixin hoặc extends). Khi thay đổi thuộc tính của model, chúng ta sẽ call notifyListeners(), khi đó ChangeNotifierProvider sẽ thông báo cho tất cả Consumer liên quan để rebuild.

class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ChangeNotifierProvider<MyModel>( create: (context) => MyModel(), child: MaterialApp( home: Scaffold( appBar: AppBar(title: Text('My App')), backgroundColor: Colors.grey, body: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Container( padding: const EdgeInsets.all(20), color: Colors.green[200], child: Consumer<MyModel>( builder: (context, mymodel, child) { return RaisedButton( child: Text('Do something'), onPressed: () { mymodel.doSomething(); }, ); }, ), ), Container( padding: const EdgeInsets.all(35), color: Colors.blue[200], child: Consumer<MyModel>( builder: (context, mymodel, child) { return Text(mymodel.text); }, ), ), ], ), ), ), ); }
} class MyModel with ChangeNotifier { String text = "Hello"; void doSomething() { text = "World"; notifyListeners(); }
}

Như vậy, khi chúng ta click button, text trên Text sẽ được change từ "Hello" sang "World". Tuy nhiên rõ ràng khi cập nhật, button cũng đang nằm trong Consumer nên sẽ bị rebuild, điều này là không cần thiết. Chúng ta ko cần sử dụng Consumer cho widget này, mà sẽ chuyển

 Consumer<MyModel>( builder: (context, mymodel, child) { return RaisedButton( child: Text('Do something'), onPressed: () { mymodel.doSomething(); }, ); }, )

thành

 RaisedButton( child: Text('Do something'), onPressed: () { Provider.of<MyModel>(context, listen: false).doSomething(); }, )

Như vậy chúng ta sẽ tránh được việc rebuild không cần thiết.

Summary

Như vậy chúng ta đã tìm hiểu cơ bản về Provider, một thư viện quản lý state trong Flutter. Hy vọng qua bài viết này các bạn có thể áp dụng vào các dự án của mình.

Cảm ơn các bạn đã đọc bài viết. Happy coding!

Ref:

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 525

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

0 0 396

- vừa được xem lúc

Đặt tên commit message sao cho "tình nghĩa anh em chắc chắn bền lâu"????

. Lời mở đầu. .

1 1 737

- vừa được xem lúc

Tìm hiểu về Resource Controller trong Laravel

Giới thiệu. Trong laravel, việc sử dụng các route post, get, group để gọi đến 1 action của Controller đã là quá quen đối với các bạn sử dụng framework này.

0 0 358

- vừa được xem lúc

Phân quyền đơn giản với package Laravel permission

Như các bạn đã biết, phân quyền trong một ứng dụng là một phần không thể thiếu trong việc phát triển phần mềm, dù đó là ứng dụng web hay là mobile. Vậy nên, hôm nay mình sẽ giới thiệu một package có thể giúp các bạn phân quyền nhanh và đơn giản trong một website được viết bằng PHP với framework là L

0 0 449

- vừa được xem lúc

Bạn đã biết các tips này khi làm việc với chuỗi trong JavaScript chưa ?

Hi xin chào các bạn, tiếp tục chuỗi chủ đề về cái thằng JavaScript này, hôm nay mình sẽ giới thiệu cho các bạn một số thủ thuật hay ho khi làm việc với chuỗi trong JavaScript có thể bạn đã hoặc chưa từng dùng. Cụ thể như nào thì hãy cùng mình tìm hiểu trong bài viết này nhé (go).

0 0 433