Flutter 2.4 - StatelessWidget & StatefulWidget
1. StatelessWidget
Đây là những widget không quan tâm đến việc thay đổi, tạo ra 1 lần duy nhất hoặc hiểu cách đơn giản hơn thì đây là widget chỉ nhận khởi tạo có sẵn rồi thực thi nó và không có thay đổi State. Ví dụ như widget Text, Center, MaterialApp, ...
Cấu trúc của một StatelessWidget như sau:
class MyWidget extends StatelessWidget { MyWidget({Key key, this.param,}) : super(key: key); String param; @override Widget build(BuildContext context) { return Container( child: Text('Hello guys'), ); } }
- Bạn có thể thấy, chúng ta có thể thêm vài tham số vào constructor. Tuy nhiên, hãy nhớ rằng những tham số này sẽ không thay đổi (immutable) ở những lần build sau.
- Lifecycle của StatelessWidget gồm:
- Khởi tạo
- Render widget thông qua build()
2. StatefulWidget
- Trái ngược với StatelessWidget thì StatefulWidget sẽ xử lí các dữ liệu bên trong nó, lắng nghe những thay đổi, dữ liệu này sẽ liên tục thay đổi (mutable) trong suốt lifecycle của widget.
- Tập hợp những dữ liệu thay đổi được giữ bởi StatefulWidget, thay đổi trong suốt lifecycle của widget và dữ liệu có thể đọc 1 cách đồng bộ khi widget đã được build thì ta gọi đó là State. State định nghĩa ra phần hành vi mà StatefulWidget thể hiện. 1 State chứa các thông tin tương tác với widget thông qua các khía cạnh về hành vi (behavior) và layout. Mỗi khi thay đổi State thì widget đó sẽ thay đổi theo.
- Giữa State và BuildContext có 1 mối quan hệ khá khăn khít. Mỗi khi 1 State được tạo ra thì nó sẽ gắn với 1 BuildContext và lúc này State là mounted.
3. StatefulWidget lifecycle
Lifecycle của StatefulWidget được thể hiện như sau:
- createState()
- mounted == true
- initState()
- didChangeDependencies()
- build()
- didUpdateWidget()
- setState()
- deactivate()
- dispose()
- mounted == false
class MyWidget extends StatefulWidget { @override _MyWidgetState createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { @override void initState() { super.initState(); } @override void didChangeDependencies() { super.didChangeDependencies(); } @override Widget build(BuildContext context) { return null; } @override void didUpdateWidget(TestMain oldWidget) { super.didUpdateWidget(oldWidget); } @override void setState(fn) { super.setState(fn); } @override void deactivate() { super.deactivate(); } @override void dispose() { super.dispose(); } }
- createState() - khi tạo ra 1 StatefulWidget thì createState() sẽ được gọi để tạo ra State cho widget và thêm widget vào widget tree.
- mounted == true - khi chúng ta đã tạo ra State thì 1 BuildContext sẽ được gán cho State.
- initState() - đây là phương thức đầu tiên được gọi lúc ta khởi tạo widget. Nó được gọi 1 và chỉ 1 lần duy nhất và khi override lại thì cần phải gọi lại super.initState(). Chúng ta sử dụng phương thức này cho:
- Khởi tạo dữ liệu cho 1 BuildContext cụ thể
- Khởi tạo các thuộc tính cho parent widget
- Khi chúng ta đăng kí 1 Stream, khởi tạo dữ liệu hoặc thay đổi dữ liệu của widget
- didChangeDependencies() - đây là phương thức tiếp theo sẽ được gọi sau khi initState() được khởi tạo. Override phương thức này có nghĩa là widget đã được liên kết với 1 InheritedWidget hoặc bạn muốn State lắng nghe sự thay đổi của widget được thừa kế . Một khi đã liên kết widget với InheritedWidget thì mỗi khi widget rebuild thì phương thức này sẽ được gọi.
- build() - đây là phương thức sẽ được gọi mỗi khi State thay đổi hoặc là khi InheritedWidget cần thông báo cho các widget đã đăng kí.
- didUpdateWidget() - phương thức được gọi nếu parent widget thay đổi hoặc có widget cần rebuild, nhưng nó cần phải cùng runtimeType. Flutter có cơ chế tái sử dụng State trong thời gian dài, do đó, trong trường hợp này ta cần khởi tạo lại dữ liệu.
- setState() - đây là phương thức mà bạn sẽ phải "vọc" khá nhiều khi làm việc với Flutter. Nó thông báo cho framework biết dữ liệu đã thay đổi và widget nên rebuild lại. setState() nhận 1 callback đồng bộ.
- deactivate() - hiếm khi ta phải đụng đến phương thức này, bởi vì nó được gọi khi 1 widget bị xóa khỏi widget tree nhưng có thể thêm vào lại nếu frame vẽ lên widget đó chưa kết thúc. Phương thức này được tạo để phục vụ việc di chuyển State từ điểm này đến điểm khác trên widget tree.
- dispose() - gọi khi State đã được xóa hoàn toàn.
- mounted == false - khi này State không thể nào remount lại được nữa.
6. StatefulWidget or StatelessWidget?
- Nếu widget của bạn sẽ phải thường xuyên thay đổi State và khi thay đổi thì widget của bạn sẽ được rebuild thì bạn nên sử dụng StatefulWidget. Còn nếu widget của bạn State từ lúc khởi tạo đến lúc kết thúc vẫn không có gì thay đổi thì bạn nên sử dụng StatelessWidget.
- Ví dụ widget của bạn là 1 TextField, bạn cần phải biết được State lúc nào nó được nhập, lúc nào nó đã được nhập xong, State của nó thay đổi liên tục. Còn nếu widget của bạn chỉ là 1 Text hiển thị thông báo và nó không bao giờ thay đổi thì bạn nên sử dụng StatelessWidget.
4. Some common widgets
Ở bài viết này mình chỉ liệt kê và giới thiệu tên vào widget thường hay dùng nên sẽ không đi sâu vào các thuộc tính của nó. Sẽ có 1 bài viết hoặc nhiều bài viết khác mình giới thiệu về các widget trong Flutter. Thế giới widget trong Flutter rất đa dạng nên 1 bài viết chẳng thể nào nói hết được sự thú vị của nó. Đây là thứ hấp dẫn mình đến với Flutter, cảm giác khi làm việc với các widget y như khi bạn chơi với một bộ lego, bạn tha hồ lắp ghép và sáng tạo với nó.
Text - hiển thị nội dung bạn muốn thông báo và bạn có thể custom nó thông qua thuộc tính style với khá nhiều thứ thú vị.
@override Widget build(BuildContext context) { return Text('Hello guys'); }
TextField - giúp bạn có thể nhập nội dung từ bàn phím.
@override Widget build(BuildContext context) { return TextField(); }
RaisedButton - nút bấm giúp bạn có thể truy cập đến các phần khác nhau tùy theo ý muốn của bạn. Widget này bắt buộc bạn phải truyền vào 1 callback cho thuộc tính onPressed.
@override Widget build(BuildContext context) { return RaisedButton(onPressed: _onPressed,); }
Scaffold - đây là 1 widget cung cấp cho bạn một giao diện hoàn chỉnh gồm phần appbar, body và 1 floatingActionButton chính hiệu Google.
@override Widget build(BuildContext context) { return Scaffold(); }
Container - widget thông dụng cung cấp 1 widget con, nó là wiget vừa có các thuộc tính để padding và có các thuộc tính để margin, width và height. Nếu sử dụng widget này bạn sẽ tốn khá nhiều thời gian để bạn ngồi canh chỉnh view sao cho đẹp nhất.
@override Widget build(BuildContext context) { return Container( child: Text('Hi guys'), ); }
Center - widget giúp bạn canh giữa cho widget con bên trong, lúc đầu mình cũng khá "bối rối" với widget này vì việc canh giữa bây giờ đã được nâng lên một tầm cao mới nhưng đến khi xài nó thì cảm thấy khá tiện lợi.
@override Widget build(BuildContext context) { return Center( child: Text('Hi guys'), ); }
Padding - widget đúng như tên của nó là padding widget con bên trong. Bạn bắt buộc phải khai báo thuộc tính padding của nó thông qua class EdgeInsetsGeometry.
@override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.all(69.96), child: Text('Hi guys'), ); }
Expanded - widget giúp bạn bọc widget con bên nó và phân vùng hiển thị để không bị bể giao diện. Nó tương tự như layout_weight bên Android.
@override Widget build(BuildContext context) { return Expanded( child: Text('Hi guys'), ); }
Row và Column - đây là 2 widget giúp bạn hiển thị tập hợp nhiều widget sắp xếp theo hàng hoặc cột. Nó tương tự như thuộc tính orientation trong LinearLayout của Android.
@override Widget build(BuildContext context) { return Row( children: <Widget>[ Text('Hello guys'), Text('This is row'), ], ); }
@override Widget build(BuildContext context) { return Column( children: <Widget>[ Text('Hello guys'), Text('This is column'), ], ); }
Okay, mong rằng 1 vài hiểu biết cơ bản của mình về Flutter sẽ giúp bạn có hiểu được Flutter là gì và các khái niệm cơ bản khi bạn tiếp cận với Flutter.
*bài viết đc trích dẫn của a Long25vn : https://gist.github.com/long25vn/f5de9acecf101e7ddb96445131285789
Nhận xét
Đăng nhận xét