返回 Skill 列表
extension
分类: 开发与工程无需 API Key

flutter-state-management

Flutter的Riverpod状态管理模式:提供者、通知器、异步状态以及与整洁架构的集成。触发条件:在创建Riverpod提供者、管理异步状态或将UI连接到移动应用中的业务逻辑时。

person作者: jakexiaohubgithub

When to Use

  • Creating any Riverpod provider or notifier
  • Managing async data (API calls, Firebase queries)
  • Handling loading/error/data states in UI
  • Connecting presentation layer to use cases

Provider Types — Decision Tree

What kind of state do you need?

Computed value from other providers?      → Provider (read-only)
Simple sync state with mutations?         → NotifierProvider
Async data (API, DB) with mutations?      → AsyncNotifierProvider
Async data (read-only, auto-fetch)?       → FutureProvider
Real-time stream (WebSocket, Firestore)?  → StreamProvider

Patterns

1. Read-Only Computed Provider

For derived/computed values. No mutations.

Example: See assets/provider_read_only.dart

2. Notifier — Sync State with Mutations

For local, synchronous state that needs to be mutated.

Example: See assets/notifier_sync.dart

3. AsyncNotifier — Async State with Mutations (MOST COMMON)

For data that comes from an API/DB and can be mutated. Uses AsyncValue.guard() for safe state transitions.

Example: See assets/async_notifier_crud.dart

4. FutureProvider — Read-Only Async Data

For async data you only need to FETCH, not mutate. Supports .family for parameterized queries.

Example: See assets/future_provider.dart

5. StreamProvider — Real-Time Data

For Firestore listeners, WebSocket streams, etc.

Example: See assets/stream_provider.dart

Consuming Providers in UI

Handle AsyncValue (CRITICAL PATTERN)

Every async provider returns AsyncValue<T>. ALWAYS handle all 3 states: loading, error, data. Two approaches: .when() method or Dart 3.0 pattern matching.

Example: See assets/async_value_consumer.dart

Clean Architecture Integration

Page (ConsumerWidget)
  → watches provider
    → provider uses use case
      → use case calls repository interface (domain)
        → repository impl (infrastructure) calls API

Wiring — Dependency Injection

Repository providers and use case providers connect clean architecture layers via Riverpod's Provider.

Example: See assets/di_wiring.dart

autoDispose vs Keep Alive

| Scenario | Use | |----------|-----| | Screen-level data (detail pages) | autoDispose — clean up when leaving | | Global state (auth, user session) | Keep alive (no autoDispose) | | Lists that are expensive to re-fetch | Keep alive or cache manually | | Form state | autoDispose — reset on navigation |

Example: See assets/auto_dispose.dart

Naming Conventions

| Element | Pattern | Example | |---------|---------|---------| | Read-only provider | {thing}Provider | currentUserProvider | | Notifier class | {Thing}Notifier | BookingFilterNotifier | | NotifierProvider | {thing}Provider | bookingFilterProvider | | AsyncNotifier class | {Thing}Notifier | PetListNotifier | | FutureProvider | {thing}Provider | caregiverDetailProvider | | StreamProvider | {thing}Provider | chatMessagesProvider | | Repository provider | {feature}RepositoryProvider | authRepositoryProvider | | Use case provider | {useCase}Provider | loginUseCaseProvider |

Anti-Patterns

| ❌ Don't | ✅ Do | |----------|-------| | ref.read in build() method | Use ref.watch to rebuild on changes | | Business logic inside the widget | Put logic in Notifier or UseCase | | Ignore loading/error states | Always handle all 3 AsyncValue states | | One giant provider file for everything | One provider file per feature | | Call API directly from provider | Provider → UseCase → Repository | | Forget autoDispose on detail pages | Use autoDispose for screen-scoped data |

Resources

  • Templates: See assets/ for provider patterns, consumer examples, and DI wiring