NGHỆ THUẬT FLUTTER : CÁC CÁCH QUẢN LÝ STATE TRONG FLUTTER – InheritedWidget
InheritedWidget là một trong những cách quản lý State (State Management) cơ bản, sơ khai nhất trong lập trình Flutter.
I. InheritedWidget dùng để làm gì ?
– Dùng để truyền data giữa Widget tổ tiên ( cha, ông.. )-ancestor widget, cho các widget con -descendant Widgets. Hình bên dưới là một ví dụ :
II. InheritedWidget hoạt động như nào ?
– Trong một cây Widget( Widget tree ), sẽ có các loại widget khác nhau ( Cha, con …), trong đó có widget cha sử dụng InheritedWidget để truyền data xuống các widget con có nhu cầu.
Dưới đây là một ví dụ, các Widget con có thể lấy data và thay đổi data của Widget cha có sử dụng InheritedWidget.
– TheStatefulWidget: là một Widget đăng ký InheritedWidget, nghĩa là data ( variables, function ) sẽ có thể được chia sẻ và can thiệp bởi các Widget con khác.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
class TheStatefulWidget extends StatefulWidget { final Widget child; TheStatefulWidget({Key key, @required this.child}):super(key: key); /// Add listener with InheritedWidget static TheStatefulWidgetState of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<TheInheritedWidget>().data; } @override TheStatefulWidgetState createState() => TheStatefulWidgetState(); } class TheStatefulWidgetState extends State<TheStatefulWidget> { bool _changed = false; bool get changed => _changed; changeColor(){ setState(() { _changed = !_changed; }); } @override Widget build(BuildContext context) { return TheInheritedWidget( child: widget.child, data: this); } } /// The InheritedWidget /// /// This Widget will be used to pass data from TheStatefulWidget to child Widgets class TheInheritedWidget extends InheritedWidget{ final TheStatefulWidgetState data; // define data of parent Widgets is: TheStatefulWidgetState TheInheritedWidget({ Key key, @required Widget child, @required this.data }) : super(key: key, child: child); @override bool updateShouldNotify(InheritedWidget oldWidget) { // TODO: implement updateShouldNotify return true; } } |
– ColorBox, LabelBox là các widget sẽ sử dụng data và tác động data từ widget : TheStatefulWidget .
Trong TheStatefulWidget chúng ta đã đăng kí sử dụng InheritedWidget, dưới đây là cách sử dụng:
* Lấy giá trị boolean: _changed
1 |
TheStatefulWidget.of(context).changed; |
* Chạy hàm changeColor():
1 |
TheStatefulWidget.of(context).changeColor; |
Dưới đây là fullcode bạn có thể chạy thử:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
import 'package:flutter/material.dart'; void main(){ return runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: TheStatefulWidget( child: TheContainer( child: TheStackWidget(), ), ) ), ); } } /// TheStatefulWidget /// /// This Widget use InheritedWidget /// This Widget contains: variables , functions /// Its child Widget will interact these variables , functions class TheStatefulWidget extends StatefulWidget { final Widget child; TheStatefulWidget({Key key, @required this.child}):super(key: key); /// Add listener with InheritedWidget static TheStatefulWidgetState of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<TheInheritedWidget>().data; } @override TheStatefulWidgetState createState() => TheStatefulWidgetState(); } class TheStatefulWidgetState extends State<TheStatefulWidget> { bool _changed = false; bool get changed => _changed; changeColor(){ setState(() { _changed = !_changed; }); } @override Widget build(BuildContext context) { return TheInheritedWidget( child: widget.child, data: this); } } /// The InheritedWidget /// /// This Widget will be used to pass data from TheStatefulWidget to child Widgets class TheInheritedWidget extends InheritedWidget{ final TheStatefulWidgetState data; // define data of parent Widgets is: TheStatefulWidgetState TheInheritedWidget({ Key key, @required Widget child, @required this.data }) : super(key: key, child: child); @override bool updateShouldNotify(InheritedWidget oldWidget) { // TODO: implement updateShouldNotify return true; } } // TheContainer is parents of ColorBox & LableBox Widget class TheContainer extends StatelessWidget { final Widget child; TheContainer({Key key, this.child}): super(key: key); @override Widget build(BuildContext context) { return child; } } /// TheStackWidget /// /// class TheStackWidget extends StatelessWidget{ @override Widget build(BuildContext context) { // TODO: implement build return Stack( children: [ ColorBox(), LableBox() ], ); } } // LableBox use data from the TheStatefulWidget class LableBox extends StatefulWidget { @override _LableBoxState createState() => _LableBoxState(); } class _LableBoxState extends State<LableBox> { bool changed; @override void didChangeDependencies() { // TODO: implement didChangeDependencies TheStatefulWidgetState data = TheStatefulWidget.of(context); changed = data.changed; super.didChangeDependencies(); } @override Widget build(BuildContext context) { return changed ? Text("Màu Đỏ", style: TextStyle( color: Colors.white ),) : Text("Màu Xanh", style: TextStyle( color: Colors.white ),); } } class ColorBox extends StatefulWidget { @override _ColorBoxState createState() => _ColorBoxState(); } class _ColorBoxState extends State<ColorBox> { bool changed ; @override void didChangeDependencies() { // TODO: implement didChangeDependencies super.didChangeDependencies(); TheStatefulWidgetState data = TheStatefulWidget.of(context); changed = data.changed; } @override Widget build(BuildContext context) { return GestureDetector( child: Container( height: 200, width: 200, decoration: BoxDecoration( color: changed ? Colors.red: Colors.blue ), ), onTap: (){ // Use function of parentWidget - TheStatefulWidget TheStatefulWidget.of(context).changeColor(); }, ); } } |
Như vậy trong việc sử dụng InheritedWidget, bạn chỉ cần nhớ 2 điều quan trọng :
– Widget nào đăng kí InheritedWidget
– Sử dụng data ở những Widget con nào
Sử dụng InheriteWidget là một cách quản lý State ( State Management ) cơ bản, giúp truyền data từ widget tổ tiên (ancestor widget ) sang các widget con cháu (descendant widget).
+ Ưu điểm của phương pháp này là rất tiện lợi, nhanh gọn đối với đoạn cây Widget nhỏ ( Widget Tree).
+ Nhược điểm của phương pháp này là khi áp dụng vào đoạn widget Tree lớn thì sẽ rất khó kiểm soát và khó triển khai.
Khi muốn triển khai trên đoạn Widget Tree lớn, chúng ta nên dùng Provider
Bạn có thể tham khảo link Github của bài viết ở đây => Github Link
Chúc các bạn có được nhiều kiến thức từ blog Báo Flutter !