Menu
CoddyTech

Tải dữ liệu một lần trong initState

Thuộc phần Dữ liệu và mạng trong hành trình Flutter của Coddy. Bài học 7 trên 27.

Flutter gọi lại build mỗi khi màn hình vẽ lại: sau mỗi lần gọi setState, khi điện thoại xoay, khi thành phần cha thay đổi. Việc này có thể xảy ra nhiều lần mỗi giây. build chỉ nên mô tả màn hình, không bao giờ bắt đầu công việc.

Vì vậy, một lệnh fetch viết bên trong build sẽ chạy lại sau mỗi lần màn hình vẽ lại. Mỗi lần chạy là một yêu cầu mới gửi đến máy chủ, và màn hình có thể chuyển sang một câu trả lời khác dù không có gì yêu cầu điều đó:

// một yêu cầu mới mỗi khi vẽ lại
FutureBuilder<String>(
  future: fetch('/tip'),
  ...
)

Hãy tạo future một lần khi màn hình mở, trong initState, rồi mỗi lần đều truyền cùng future đó cho FutureBuilder:

late Future<String> _tip;

@override
void initState() {
  super.initState();
  _tip = fetch('/tip');
}

initState chạy một lần trước build đầu tiên. Hãy bắt đầu bằng super.initState(); theo yêu cầu của Flutter.

challenge icon

Thử thách

Trung bình

Chạm vào biểu tượng trái tim trên thanh trên cùng: mẹo thay đổi vì fetch nằm trong build. Chỉ tải mẹo một lần:

  • thêm late Future<String> _tip; vào trạng thái
  • gán giá trị cho nó trong initState bằng fetch('/tip')
  • truyền _tip cho FutureBuilder

Tự làm thử

import 'package:flutter/material.dart';

import 'api.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: TipScreen(),
    );
  }
}

class TipScreen extends StatefulWidget {
  const TipScreen({super.key});

  @override
  State<TipScreen> createState() => _TipScreenState();
}

class _TipScreenState extends State<TipScreen> {
  bool liked = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tip of the Day'),
        actions: [
          IconButton(
            icon: Icon(liked ? Icons.favorite : Icons.favorite_border),
            onPressed: () {
              setState(() {
                liked = !liked;
              });
            },
          ),
        ],
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: FutureBuilder<String>(
              future: fetch('/tip'),
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Text(
                    snapshot.data!,
                    textAlign: TextAlign.center,
                    style: const TextStyle(fontSize: 24),
                  );
                }
                return const CircularProgressIndicator();
              },
            ),
        ),
      ),
    );
  }
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Dữ liệu và mạng

Tự luyện tập: Trình biên dịch Flutter online