인터페이스는 현지화되어 있으며, Skill 소개와 설명 문서는 선택한 언어로 AI가 자동 번역합니다. 코드·명령어·경로·전문 용어는 원문을 유지하며 원작자 문서가 우선합니다.
Skills 둘러보기
개발 및 엔지니어링 · SKILL.md

riverpod-patterns

riverpod-patterns

This skill provides Riverpod state management patterns and best practices for Flutter applications. Use when reviewing or writing Riverpod providers, AsyncValue handling, ref usage, or provider lifecycle management.

Independent GitHub snapshot · Automated classification · Original documentation governs

Skill 문서

GitHub

name: riverpod-patterns description: "This skill provides Riverpod state management patterns and best practices for Flutter applications. Use when reviewing or writing Riverpod providers, AsyncValue handling, ref usage, or provider lifecycle management." allowed-tools: Read metadata: triggers: Riverpod, Flutter state management, Riverpod provider, AsyncValue, StateNotifier, ConsumerWidget, AsyncNotifier related-skills: flutter-mobile, ui-standards-tokens domain: frontend role: specialist scope: implementation output-format: code last-reviewed: "2026-03-15"

Iron Law: Always use the correct Riverpod provider type for the use case; never use StateProvider for async data or FutureProvider for mutable state.

Riverpod Patterns

Correct Riverpod patterns for Flutter state management with code_generation style.

When to use: Writing or reviewing Riverpod providers, AsyncNotifier, AsyncValue.when, ref.watch vs ref.read, family providers, or provider lifecycle.

Process:

  1. Identify pattern needed from user request
  2. Load reference: Read reference/riverpod-core-patterns.md for code examples and rules
  3. Apply patterns using loaded reference
  4. Verify: Confirm ref.watch is only in build(), ref.read only in callbacks, all AsyncValue states handled visibly

Quick Reference — Most Common Patterns

Provider Type Selection

// ✅ Read-only async data (API call, DB read)
@riverpod
Future<List<User>> userList(UserListRef ref) async {
  return ref.watch(userRepositoryProvider).getAll();
}

// ✅ Mutable state with async operations
@riverpod
class UserNotifier extends _$UserNotifier {
  @override
  Future<User> build(String userId) async {
    return ref.watch(userRepositoryProvider).getById(userId);
  }

  Future<void> update(UserUpdateDto dto) async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() =>
      ref.read(userRepositoryProvider).update(dto));
  }
}

// ❌ WRONG — never use StateProvider for async data
final userProvider = StateProvider<User?>((ref) => null); // no async support

AsyncValue.when — All 3 states required

// ✅ All 3 states handled visibly
ref.watch(userListProvider).when(
  data: (users) => UserListWidget(users: users),
  loading: () => const CircularProgressIndicator(),
  error: (err, stack) => ErrorWidget(message: err.toString()), // never swallow
);

// ❌ WRONG — skipLoadingOnReload hides loading state from user
ref.watch(userListProvider).when(
  skipLoadingOnReload: true, // only acceptable after explicit UX decision
  data: (users) => UserListWidget(users: users),
  loading: () => const SizedBox.shrink(), // invisible loading = silent failure
  error: (err, stack) => const SizedBox.shrink(), // swallowed error
);

ref.watch vs ref.read

// ✅ ref.watch — only inside build()
@override
Widget build(BuildContext context, WidgetRef ref) {
  final users = ref.watch(userListProvider); // rebuilds on change
  return UserListWidget(users: users.valueOrNull ?? []);
}

// ✅ ref.read — only inside callbacks/event handlers
void onButtonPressed(WidgetRef ref) {
  ref.read(userNotifierProvider.notifier).refresh(); // one-time action
}

// ❌ WRONG — ref.watch in a callback (causes infinite rebuild)
onPressed: () => ref.watch(userNotifierProvider.notifier).refresh(),

Reference Files

FileContentsLoad When
reference/riverpod-core-patterns.mdCode examples, provider types, ref usage rulesWriting providers, ref.watch/read, AsyncValue handling
reference/riverpod-review-checklist.mdReview checklist for Riverpod code audits (used by riverpod-reviewer agent)Reviewing Riverpod code, running riverpod-reviewer agent

Error Handling

Provider not found: Ensure ProviderScope wraps the widget tree. Check that generated .g.dart files are up to date (dart run build_runner build).

AsyncValue stuck loading: Verify the repository method returns data. Use AsyncValue.guard() to catch and surface errors instead of silent failures.

저장한 Skills