Home Coding BuildContext

BuildContext

by Khanh Tran

Trong mỗi Flutter widget luôn có một @override build() method với một đối số là BuildContext. Một BuildContext như là một tham chiếu (reference) đến cái vị trí của widget (widget’s location) trong widget tree. Như chúng ta đã biết ở bài trước, mỗi loại widget đều có hàm build(), mỗi hàm build đều nhận 1 BuildContext làm argument. Như vậy mỗi Widget đều có 1 BuildContext đại diện cho vị trí của chính Widget đó trên widget tree

class CartItemWidget extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
  // ...

Why BuildContext()

Giải thích một cách đơn giản BuildContextlà vị trí của widgettrong widget tree. Chúng ta cần hiểu là:

  1. Mỗi Widget đều có một phương thức build()context của nó.
  2. BuildContext là parent của widget được returned bởi build() method.

Nói cách khác: buildContext của widget gọi build() không giống như build context của widget được returned bởi build().

Ví dụ thêm để dễ hiểu hơn nhé:

class _MyHomePageState extends State<MyHomePage> {
  _MyHomePageState() {
    print(context.hashCode);
    // prints 2011
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Container(),
      floatingActionButton:
          new FloatingActionButton(onPressed: () => print(context.hashCode)),
          // prints 63
    );
  }
}

Nếu bạn thử print các context như ví dụ trên đây, các giá trị bạn nhận được có thể sẽ khác của tôi, nhưng đó là những con số thực tế mà tôi nhận được và đã chứng minh được nội dung phía trên về phạm vi của BuildContext.

Nhưng điều này có ý nghĩa gì? Nó sẽ dễ gây ra việc truyền sai context, dễ bị reference sai build(), cũng dẫn đến những tình huống không mong muốn, cụ thể là khi sử dụng phương thức of()

‘of()’ Method

Trong Flutter, mọi thứ đều là widget, trong một số trường hợp, từ một Widget này ta cần tham chiếu các Widget khác. Điều này là bắt buộc đối với một số chức năng.

Đặc biệt, các widget khi muốn sử dụng State của inherited, widget cần có khả năng tham chiếu đến các widget được kế thừa. Điều này thường được thực hiện thông qua ofmethod.

@override
Widget build(context) {
  return new Text('Hello, World',
    style: new TextStyle(color: Theme.of(context).primaryColor),
  );
}

Với scaffold, Flutter cung cấp cho chúng ta một cách hay để giải quyết vấn đề:

Khi tạo một widget, ví dụ như một snackbar, bạn cần sử dụng Scaffold context để tạo một snackbar. Scaffold là widget dễ dàng cho chúng ta có thể access và display một snackbars.

@override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text(widget.title),
        ),
        body: new Container(),
        /// Scaffold doesn't exist in this context here
        /// because the context thats passed into 'build'
        /// refers to the Widget 'above' this one in the tree,
        /// and the Scaffold doesn't exist above this exact build method
        ///
        /// This will throw an error:
        /// 'Scaffold.of() called with a context that does not contain a Scaffold.'
        floatingActionButton: new FloatingActionButton(onPressed: () {
          Scaffold.of(context).showSnackBar(
                new SnackBar(
                  content: new Text('SnackBar'),
                ),
              );
        }));
  }

Builder Methods

Builderlà một widget đóng gói và ta có thể sử dụng nó để đóng gói các widget con. Bạn có thể sử dụng để chuyền context từ một phương thức build trực tiếp đến các widget con được return trong phương thức build đó.

Ví dụ:

@override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Container(),
      /// Builders let you pass context
      /// from your *current* build method
      /// Directly to children returned in this build method
      ///
      /// The 'builder' property accepts a callback
      /// which can be treated exactly as a 'build' method on any
      /// widget
      floatingActionButton: new Builder(builder: (context) {
        return new FloatingActionButton(onPressed: () {
          Scaffold.of(context).showSnackBar(
                new SnackBar(
                  backgroundColor: Colors.blue,
                  content: new Text('SnackBar'),
                ),
              );
        });
      }),
    );
  }

Bạn cũng có thể giải quyết vấn đề này bằng cách đơn giản là làm cho các phương thức build của bạn nhỏ lại và trả về một Scaffold trong một “higher” widget. 

You may also like

1 comment

StatefulWidget lifecycle - Blog Lập Trình StatefulWidget lifecycle 26 November, 2020 - 4:13 am

[…] bài tiếp theo: BuildContext. […]

Reply

Leave a Comment