Tìm hiểu Keys trong Flutter

Trong bài viết này, chúng ta sẽ cùng nhau khám phá các Keys trong Flutter. Không những tìm hiểu công dụng của từng loại Key, chúng ta còn biết được khi nào, ở đâu và sử dụng loại nào là thích hợp để giải quyết các vấn đề cũng như nó đã tối ưu ứng dụng của chúng ta như thế nào.

1. Khi nào nên sử dụng Key

Về cơ bản, các bạn có thể dễ dàng nhận thấy được Key được sử dụng trong bất kỳ hàm dựng của mọi Widget. Tuy nhiên, bạn cũng hiếm khi sử dụng Key trong khi thực hiện lồng ghép các Widget lại với nhau để dựng layout (đoán thui :v). Các key duy trì State khi các Widget di chuyển trong Widget tree của ứng dụng Flutter. Dưới đây là một số ví dụ cụ thể:

Dart

class NewStatelessWidget extends StatelessWidget {
  const NewStatelessWidget({ Key? key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      
    );
  }
}

Dart

class NewStatefulWidget extends StatefulWidget {
  const NewStatefulWidget({ Key? key }) : super(key: key);

  @override
  _NewStatefulWidgetState createState() => _NewStatefulWidgetState();
}

class _NewStatefulWidgetState extends State<NewStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    return Container(
      
    );
  }
}

Dart

ListTile(
  key: UniqueKey(),
  title: Text(
     text,
     style: textStyle ?? Theme.of(context).textTheme.bodyText2,
  ),
)

Dưới đây mình sẽ recap lại một tí về video trên (Lưu ý mình có thay đổi tên các class). Đầu tiên, chúng ta có 1 class StatefulWidget tên là PositionedKey. Ở phiên bản đầu tiên, hàm initState() nhận vào 2 Widget có cùng tên class là StatelessColorful. Đọc tên thôi cũng biết đây là StatelessWidget. Mục đích là hiển thị 2 ô có màu khác nhau trên màn hình trên cùng 1 dòng (nhìn ở dưới hàm build thì nó được bỏ vào 1 cái Row).

Dart

import 'package:flutter/material.dart';
import 'dart:math';
class PositionedKey extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => PositionedKeyState();
}
class PositionedKeyState extends State<PositionedKey> {
  List<Widget> tiles;
  
@override
  void initState() {
    super.initState();
    tiles = [
      StatelessColorful(),
      StatelessColorful(),
    ];
  }
@override
  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
            child: Center(
                child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: tiles))),
        floatingActionButton: FloatingActionButton(
            child: Icon(Icons.sentiment_very_satisfied), onPressed: swapTiles));
  }
  
  void swapTiles(){
  	setState(() {
      tiles.insert(1,tiles.removeAt(0));
    });
  }

Sau đó, khi ta nhấn vào floatingActionButton, hàm onPressed sẽ gọi đến function swapTiles() để hoán đổi vị trí của 2 ô và dĩ nhiên là nó work như chúng ta mong muốn.

Một điều lưu ý mà team Flutter có nói trong video đó là:

Remember, if the entire widget subtree in your collection is stateless, keys aren’t needed.

(Tạm dịch: Key sẽ không cần thiết nếu như các widget subtree là các StatelessWidget).

Bạn có thể tham khảo code khởi tạo class StatelessColorful như sau:

Dart

class StatelessColorful extends StatelessWidget {
  final Color color = UniqueColorGenaretor.getColor();
StatelessColorful({Key key}) : super(key: key);
@override
  Widget build(BuildContext context) => buildColorful(color);
}

Vậy trong trường hợp StatefulWidget thì sao? Chúng ta sẽ thay đổi class ở trong hàm initState() thành class StatefulColorful. Sau đó chúng ta nhấn vào floatingActionButton, hàm onPressed sẽ gọi đến function swapTiles() và bạn sẽ thấy một điều kỳ lạ xảy ra, đó là không có gì xảy ra hay thay đổi gì cả :))).

Dart

class StatefulColorful extends StatefulWidget {
  StatefulColorful({Key key}) : super(key: key);
@override
  State<StatefulWidget> createState() => StatefulColorfulState();
}
class StatefulColorfulState extends State<StatefulColorful> {
  Color color;
@override
  void initState() {
    super.initState();
    color = UniqueColorGenaretor.getColor();
  }
@override
  Widget build(BuildContext context) => buildColorful(color);
}

Khi ta chuyển sang sử dụng StatefulWidget thì lúc này biến color đã được lưu trữ ở trong State rồi, cho nên dù có nhấn bao nhiêu lần thì vẫn vậy, giống như crush của bạn trong State (lòng, trái tim, v.v) có chứa người khác rồi :v.

Sau khi chuyển sang StatefulWidget

Ok tình hình có vẻ không khả thi với cách cũ, ta nên thay đổi cách tiếp cận mới để đạt được kết quả mới. Mọi vấn đề chỉ cần xác định đâu là KeyPoint để giải quyết, và lần này may mắn ta chỉ cần dùng Key là giải quyết được (nhớ tìm đâu là Key để mở khoá trái tim nàng nha mấy ông :v).

Dart

void initState() {
  super.initState();
  tiles = [
    StatefulColorfulTile(key: UniqueKey()),
    StatefulColorfulTile(key: UniqueKey()),
  ];
}

Sau khi thêm, bạn hãy chạy lại code (nhớ Restart App nhé), bạn sẽ thấy chúng đã hoán đổi vị trí với nhau. Vấn đề nằm ở chỗ khi bạn hoán đổi vị trí mà không có Key, Flutter không thể nào phân biệt được sự thay đổi mà update lại đúng reference.

2. Sử dụng Key ở đâu sao cho hợp lý:

Thông thường, nó phải được đặt trong Widget cấp cao (high-level) của cây Widget hiện tại. Trong ví dụ trên, ta bọc thêm Padding cho mỗi StatefulColorful. Sau đó ta nhấn lại thì thấy màu của hai ô đã thay đổi ngẫu nhiên trong khi chúng ta muốn nó phải cố định.

3. Tổng hợp Key trong Flutter

  1. Chúng cho phép các Widget thay đổi parents của chúng ở bất kỳ vị trí nào trong ứng dụng mà không bị mất state hoặc chúng có thể được sử dụng để truy cập dữ liệu để lấy thông tin của một Widget bất kỳ.
  2. Trong trường hợp thứ hai, bạn có thể cần kiểm tra mật khẩu; tuy nhiên, bạn không muốn chia sẻ status data với các widget khác nhau trong cây và bạn có thể sử dụng GlobalKey<FromState>, nó nắm giữ State của Form.

Sự thật mà nói, GlobalKey giống như một biến toàn cục. Có những cách khác tốt hơn để hoàn thành công việc của các key đó, chẳng hạn như inherited widget, Redux, or block pattern.

Tóm lại:

Trong bài viết, tôi đã giải thích cấu trúc cơ bản của Keys In Flutter, bạn có thể sửa đổi code này theo sự lựa chọn của mình và đây là phần giới thiệu cơ bản về Keys In Flutter từ tôi và cách hoạt động của nó trong Flutter.

Bài viết được dịch và viết lại từ bài gốc: Keys In Flutter

Exit mobile version