Skip to content

Instantly share code, notes, and snippets.

@mono0926
Created March 4, 2026 01:16
Show Gist options
  • Select an option

  • Save mono0926/aff3e4749d9173719a8168998d776876 to your computer and use it in GitHub Desktop.

Select an option

Save mono0926/aff3e4749d9173719a8168998d776876 to your computer and use it in GitHub Desktop.
自動生成されたRiverpodスキル
name description metadata
Riverpod
Riverpodをスムーズに使いこなすためのスキル
model last_modified
models/gemini-3.1-pro-preview
Wed, 04 Mar 2026 01:15:48 GMT

riverpod-state-management

Goal

Configures and implements the Riverpod reactive caching and data-binding framework for Dart and Flutter applications. Handles dependency resolution, provider generation, state consumption, and enforces strict static analysis rules via riverpod_lint to ensure predictable, scalable, and testable asynchronous state management.

Decision Logic

Before implementing Riverpod, determine the target architecture using the following logic:

  1. Target Platform: Is the application pure Dart or Flutter?
  2. Hooks: Does the application use flutter_hooks? (If yes, requires hooks_riverpod).
  3. Code Generation: Is code generation preferred? (Highly recommended; requires riverpod_annotation and riverpod_generator).

Instructions

  1. Determine Environment and Architecture STOP AND ASK THE USER: "Please specify your environment preferences for Riverpod: 1. Flutter or pure Dart? 2. Do you want to use flutter_hooks? 3. Do you want to use code generation (riverpod_generator)?"

  2. Configure Dependencies Based on the user's response, inject the exact dependencies into pubspec.yaml.

    For Flutter + Code Gen (Standard Recommended):

    dependencies:
      flutter:
        sdk: flutter
      flutter_riverpod: ^3.2.1
      riverpod_annotation: ^4.0.2
    
    dev_dependencies:
      build_runner:
      riverpod_generator: ^4.0.3

    For Flutter + Hooks + Code Gen:

    dependencies:
      flutter:
        sdk: flutter
      hooks_riverpod: ^3.2.1
      flutter_hooks:
      riverpod_annotation: ^4.0.2
    
    dev_dependencies:
      build_runner:
      riverpod_generator: ^4.0.3
  3. Enable Strict Linting Configure riverpod_lint to enforce framework rules. Create or update analysis_options.yaml at the project root:

    analyzer:
      plugins:
        - custom_lint
    
    dependencies:
      custom_lint:
      riverpod_lint: ^3.1.3
  4. Initialize the Root Scope Initialize the state container at the entry point of the application.

    For Flutter:

    import 'package:flutter/material.dart';
    import 'package:flutter_riverpod/flutter_riverpod.dart';
    
    void main() {
      runApp(
        const ProviderScope(
          child: MyApp(),
        ),
      );
    }

    For Pure Dart:

    import 'package:riverpod/riverpod.dart';
    
    void main() {
      final container = ProviderContainer();
      // Use container.read(...) to access providers
    }
  5. Define Providers Implement providers using the chosen architecture.

    Using Code Generation (Functional):

    import 'package:riverpod_annotation/riverpod_annotation.dart';
    import 'package:http/http.dart' as http;
    import 'dart:convert';
    
    part 'activity_provider.g.dart';
    
    @riverpod
    Future<String> boredSuggestion(Ref ref) async {
      final response = await http.get(
        Uri.https('boredapi.com', '/api/activity'),
      );
      final json = jsonDecode(response.body);
      return json['activity']! as String;
    }

    Using Code Generation (Class-based Notifier):

    import 'package:riverpod_annotation/riverpod_annotation.dart';
    
    part 'counter_provider.g.dart';
    
    @riverpod
    class Counter extends _$Counter {
      @override
      int build() => 0;
    
      void increment() => state++;
    }
  6. Consume Providers in the UI Bind the UI to the providers and handle asynchronous states gracefully.

    Using ConsumerWidget:

    class Home extends ConsumerWidget {
      const Home({super.key});
    
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        final suggestion = ref.watch(boredSuggestionProvider);
        
        return switch (suggestion) {
          AsyncData(:final value) => Text('Data: $value'),
          AsyncError(:final error) => Text('Error: $error'),
          _ => const CircularProgressIndicator(),
        };
      }
    }

    Using HookConsumerWidget (if hooks are enabled):

    class Home extends HookConsumerWidget {
      const Home({super.key});
    
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        final counter = useState(0);
        final suggestion = ref.watch(boredSuggestionProvider);
        
        return Text('Local: ${counter.value}, Async: ${suggestion.valueOrNull}');
      }
    }
  7. Validate and Fix Review the generated code against the riverpod_lint rules. If any constraints (listed below) are violated, immediately refactor the code to comply.

Constraints

  • Scope Requirement: Flutter applications MUST have a ProviderScope at the root of the widget tree.
  • No BuildContext in Providers: Providers and Notifiers MUST NOT receive or interact with BuildContext.
  • Notifier Encapsulation: Notifier and AsyncNotifier classes MUST NOT expose public properties or getters outside of the state property. All state mutations must happen via methods that update state.
  • Notifier Inheritance: Classes annotated with @riverpod MUST extend _$ClassName and MUST implement a build() method.
  • Functional Ref Naming: Functional providers MUST receive a Ref object as their first positional parameter, and it MUST be named ref.
  • Parameter Equality: Provider parameters MUST have a consistent == operator. Use constant objects or override == and hashCode for custom parameter classes.
  • KeepAlive Dependencies: A provider marked with keepAlive: true MUST NOT depend on a provider that is auto-disposed (non-keepAlive).
  • Dispose Safety: Do NOT use ref.read() or ref.watch() inside the dispose() method of a ConsumerState.
  • Scoped Dependencies: If a provider depends on other scoped providers, it MUST explicitly list them using @Riverpod(dependencies: [otherProvider]).
  • Cross-Notifier State Access: Notifiers MUST NOT access the protected properties (.state, .future, .ref) of other notifiers. Use exposed public methods for cross-notifier interactions.
  • Nullable Async Patterns: Do NOT use the pattern AsyncValue(:final value?) if the underlying data type is nullable. Use AsyncValue(:final value, hasValue: true) instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment