Menu
CoddyTech

Các provider theo dõi provider khác

Thuộc phần Quản lý trạng thái trong hành trình Flutter của Coddy. Bài học 20 trên 27.

Một số trạng thái được suy ra từ trạng thái khác: tổng số phút bằng tổng thời lượng các buổi tập. Bạn có thể cộng chúng lại trong từng widget hiển thị tổng, hoặc viết một lần dưới dạng provider theo dõi một provider khác:

final totalMinutesProvider = Provider((ref) {
  final workouts = ref.watch(workoutsProvider);
  return workouts.fold(0, (sum, w) => sum + w.minutes);
});

Hàm của một provider cũng nhận ref. Khi dùng ref.watch bên trong hàm, Riverpod ghi nhớ rằng tổng phụ thuộc vào các buổi tập. Khi thêm một buổi tập, tổng sẽ được tính lại và mọi widget theo dõi tổng cũng sẽ dựng lại.

Ở đây, hãy dùng ref.watch, không dùng ref.read. read chỉ lấy danh sách một lần, khi tính tổng lần đầu, nên tổng sẽ không bao giờ thay đổi sau đó.

Đây là ý tưởng getter đã học trước đó, áp dụng cho toàn bộ ứng dụng: chỉ lưu những gì cần thiết nhất có thể, rồi tính phần còn lại từ đó.

challenge icon

Thử thách

Trung bình

Thanh trên cùng theo dõi totalMinutesProvider, nhưng provider đó luôn trả về 0.

  • Hãy để nó theo dõi workoutsProvider và trả về tổng số minutes của mọi buổi tập.

Tự làm thử

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class Workout {
  Workout(this.name, this.minutes);

  final String name;
  final int minutes;
}

class WorkoutLog extends Notifier<List<Workout>> {
  @override
  List<Workout> build() => [];

  void add(Workout workout) {
    state = [...state, workout];
  }
}

final workoutsProvider = NotifierProvider<WorkoutLog, List<Workout>>(WorkoutLog.new);

final totalMinutesProvider = Provider((ref) {
  return 0;
});

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

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

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

class LogPage extends ConsumerWidget {
  const LogPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final workouts = ref.watch(workoutsProvider);
    final total = ref.watch(totalMinutesProvider);
    return Scaffold(
      appBar: AppBar(title: Text('Total: $total min')),
      body: Column(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () => ref.read(workoutsProvider.notifier).add(Workout('Run', 30)),
                child: const Text('Run'),
              ),
              const SizedBox(width: 16),
              ElevatedButton(
                onPressed: () => ref.read(workoutsProvider.notifier).add(Workout('Yoga', 20)),
                child: const Text('Yoga'),
              ),
            ],
          ),
          Expanded(
            child: ListView(
              children: [
                for (final w in workouts) ListTile(title: Text(w.name), trailing: Text('${w.minutes} min')),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
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 Quản lý trạng thái

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