riverpod annotation

topics 500-모바일개발 501 Flutter 504 Riverpod
types 실습 레퍼런스
tags
references codewithandrea.com/articles/flutter-r... q.agency/blog/migrating-from-statenot... riverpod.dev/docs/concepts/about_code...

Riverpod Annotation

Riverpod 2.0에서 추가된 어노테이션 기반 코드 생성 방식이다.

설치

dependencies:
  flutter_riverpod: ^2.4.0
  riverpod_annotation: ^2.3.0

dev_dependencies:
  riverpod_generator: ^2.3.0
  build_runner: ^2.4.0

기본 Provider

이전 방식

final helloProvider = Provider<String>((ref) {
  return 'Hello';
});

어노테이션 방식

part 'hello.g.dart';

@riverpod
String hello(HelloRef ref) {
  return 'Hello';
}

장점: 타입 추론이 자동으로 되고, 코드가 더 간결하다.

Family Provider

파라미터를 받는 Provider다.

이전 방식

final movieProvider = FutureProvider.family<Movie, int>((ref, movieId) async {
  return ref.watch(moviesRepositoryProvider).movie(movieId: movieId);
});

어노테이션 방식

@riverpod
Future<Movie> movie(MovieRef ref, {required int movieId}) {
  return ref.watch(moviesRepositoryProvider).movie(movieId: movieId);
}

왜 이게 좋냐면: family를 명시적으로 작성할 필요가 없다. 파라미터가 있으면 자동으로 family provider로 생성된다.

Notifier

상태를 변경하는 Provider다.

이전 방식

final counterProvider = NotifierProvider<CounterNotifier, int>(() {
  return CounterNotifier();
});

class CounterNotifier extends Notifier<int> {
  @override
  int build() => 0;

  void increment() => state++;
}

어노테이션 방식

part 'counter.g.dart';

@riverpod
class Counter extends _$Counter {
  @override
  int build() => 0;

  void increment() => state++;
}

AsyncNotifier

비동기 상태를 다루는 Notifier다.

@riverpod
class UserNotifier extends _$UserNotifier {
  @override
  Future<User> build() async {
    return await ref.watch(userRepositoryProvider).getCurrentUser();
  }

  Future<void> updateName(String name) async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async {
      final user = state.value!;
      final updated = user.copyWith(name: name);
      await ref.read(userRepositoryProvider).update(updated);
      return updated;
    });
  }
}

keepAlive

Provider가 dispose되지 않도록 유지한다.

@Riverpod(keepAlive: true)
Future<Database> database(DatabaseRef ref) async {
  return await openDatabase();
}

코드 생성

# <span id="한번만-빌드"></span>한번만 빌드
dart run build_runner build

# <span id="파일-변경-감지"></span>파일 변경 감지
dart run build_runner watch

# <span id="충돌-해결"></span>충돌 해결
dart run build_runner build --delete-conflicting-outputs

테스트

void main() {
  test('counter increments', () {
    final container = ProviderContainer();
    addTearDown(container.dispose);

    expect(container.read(counterProvider), 0);

    container.read(counterProvider.notifier).increment();

    expect(container.read(counterProvider), 1);
  });
}

관련 문서