Menu
CoddyTech

다른 Provider를 감시하는 Provider

Coddy Flutter 여정의 상태 관리 섹션에 포함된 레슨. 27개 중 20번째.

일부 상태는 다른 상태에서 계산됩니다. 총 시간(분)은 운동 시간의 합입니다. 총계를 표시하는 모든 위젯에서 이를 더할 수도 있고, 다른 프로바이더를 감시하는 프로바이더로 한 번만 작성할 수도 있습니다.

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

프로바이더의 함수도 ref를 받습니다. 함수 안에서 ref.watch를 사용하면 Riverpod은 총계가 운동에 따라 달라진다는 것을 기억합니다. 운동을 추가하면 총계를 다시 계산하고, 총계를 감시하는 모든 위젯도 다시 빌드됩니다.

여기서는 ref.read가 아니라 ref.watch를 사용하세요. read는 총계를 처음 계산할 때 목록을 한 번 가져오므로, 그 뒤로 총계는 바뀌지 않습니다.

이것이 앞서 살펴본 게터의 개념을 앱 전체에 적용한 것입니다. 가능한 한 적은 상태만 저장하고, 나머지는 그 상태를 바탕으로 계산하세요.

challenge icon

챌린지

중급

상단 표시줄은 totalMinutesProvider를 감시하지만, 해당 프로바이더는 항상 0을 반환합니다.

  • workoutsProvider를 감시하고 모든 운동의 minutes 합계를 반환하도록 하세요.

직접 해보기

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 icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

상태 관리의 모든 레슨

직접 연습해 보세요: 온라인 Flutter 컴파일러