riverpod-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRiverpod Best Practices (v3)
Riverpod最佳实践(v3)
This skill outlines the standard operating procedures for using Riverpod v3 in this project. Adherence to these practices ensures maintainability, testability, and consistency.
本技能概述了在项目中使用Riverpod v3的标准操作流程。遵循这些实践可确保代码的可维护性、可测试性和一致性。
Core Principles
核心原则
- Code Generation (): ALWAYS use the
@riverpodannotation and@riverpod. Do NOT define providers manually (e.g.,riverpod_generator).Provider((ref) => ...)- Why: Reduces boilerplate, handles logic automatically, ensures type safety, and enables easier refactoring.
autoDispose
- Why: Reduces boilerplate, handles
- Modular Architecture: Organize code by feature, not by layer.
- Structure: for providers,
lib/modules/[feature]/providers/for UI.lib/modules/[feature]/screens/
- Structure:
- Unified : Use
Reffor all provider interactions. Avoid legacy types likeRefinside providers (useWidgetRefinstead).Ref - AsyncValue First: Always handle Loading/Error/Data states explicitly in the UI using expressions.
switch
- 代码生成(): 务必使用
@riverpod注解和@riverpod。不要手动定义providers(例如:riverpod_generator)。Provider((ref) => ...)- 原因: 减少样板代码,自动处理逻辑,确保类型安全,便于重构。
autoDispose
- 原因: 减少样板代码,自动处理
- 模块化架构: 按功能而非层级组织代码。
- 结构: 存放providers,
lib/modules/[feature]/providers/存放UI。lib/modules/[feature]/screens/
- 结构:
- 统一使用: 所有provider交互都使用
Ref。避免在provider内部使用Ref等旧类型(改用WidgetRef)。Ref - 优先使用AsyncValue: 在UI中始终使用表达式显式处理加载/错误/数据状态。
switch
Implementation Guidelines
实现指南
1. Defining Providers
1. 定义Providers
- Class-Based (Notifier): Use for complex state requiring methods (mutations).
dart
class MyNotifier extends _$MyNotifier { ... } - Functional (Future/Stream): Use for simple data fetching or read-only values.
dart
Future<Data> myData(Ref ref) async { ... } - KeepAlive: Use ONLY for global state (User, Auth, Settings). Default is
@Riverpod(keepAlive: true).autoDispose
- 基于类的(Notifier): 用于需要方法(变更操作)的复杂状态。
dart
class MyNotifier extends _$MyNotifier { ... } - 函数式(Future/Stream): 用于简单的数据获取或只读值。
dart
Future<Data> myData(Ref ref) async { ... } - KeepAlive: 仅对全局状态(用户、认证、设置)使用。默认使用
@Riverpod(keepAlive: true)。autoDispose
2. State Management
2. 状态管理
- Side Effects: Perform side effects (API calls, navigation logic) in methods within the Notifier, NOT in the method.
build() - Ref.mounted: Always check after an
ref.mountedbefore setting state to prevent exceptions on disposed providers.awaitdartif (ref.mounted) state = AsyncData(data); - Mutations: To update lists/data, prefer fetching fresh data or optimistically updating state.
- 副作用: 在Notifier内部的方法中执行副作用(API调用、导航逻辑),不要在方法中执行。
build() - Ref.mounted: 在之后设置状态前,务必检查
await,以避免已销毁的provider引发异常。ref.mounteddartif (ref.mounted) state = AsyncData(data); - 变更操作: 更新列表/数据时,优先获取最新数据或乐观更新状态。
3. Consuming Providers
3. 使用Providers
- ConsumerWidget: Extend instead of
ConsumerWidget.StatelessWidget - ConsumerStatefulWidget: Extend if you need
ConsumerStatefulWidget/initState.dispose - Ref.watch: Use inside
ref.watchto rebuild on changes.build() - Ref.read: Use inside callbacks (e.g.,
ref.read) to trigger actions. NEVER useonPressedinsideref.read.build()
- ConsumerWidget: 继承而非
ConsumerWidget。StatelessWidget - ConsumerStatefulWidget: 如果需要/
initState,则继承dispose。ConsumerStatefulWidget - Ref.watch: 在内部使用
build(),以便在状态变化时重建组件。ref.watch - Ref.read: 在回调(如)中使用
onPressed来触发操作。绝对不要在ref.read内部使用build()。ref.read
4. Naming Conventions
4. 命名规范
- File Name: (e.g.,
snake_case).user_controller.dart - Class Name: (e.g.,
PascalCase).UserController - Provider Name (Generated): (e.g.,
camelCase).userControllerProvider
- 文件名: 使用(例如:
蛇形命名法(snake_case))。user_controller.dart - 类名: 使用(例如:
大驼峰命名法(PascalCase))。UserController - 生成的Provider名称: 使用(例如:
小驼峰命名法(camelCase))。userControllerProvider
Resources
资源
- Code Snippets: See references/snippets.md for templates of Notifiers, Providers, and Consumers.
- Testing Guide: See references/testing.md for unit and widget testing patterns.
- Async Gaps & Lifecycle: See references/async_gaps.md for critical info on and
UnmountedRefException.keepAlive - Provider Types: See references/provider_types.md for a decision tree on which provider to use.
- Performance: See references/performance.md for and optimization tips.
ref.select - Architecture: See references/architecture.md for repository patterns and anti-patterns.
- 代码片段: 查看references/snippets.md获取Notifiers、Providers和Consumers的模板。
- 测试指南: 查看references/testing.md获取单元测试和组件测试模式。
- 异步间隙与生命周期: 查看references/async_gaps.md获取关于和
UnmountedRefException的重要信息。keepAlive - Provider类型: 查看references/provider_types.md获取选择provider的决策树。
- 性能优化: 查看references/performance.md获取和优化技巧。
ref.select - 架构设计: 查看references/architecture.md获取仓库模式和反模式相关内容。
Migration (from v2/Manual)
迁移指南(从v2/手动实现)
If you encounter manual providers (, , etc.):
StateNotifierProviderChangeNotifierProvider- Identify: Locate the logic.
- Convert: Rewrite as a class or function.
@riverpod - Replace: Update consumers to use the generated provider (e.g., instead of
myProviderfor watching state).myProvider.notifier
如果遇到手动实现的providers(、等):
StateNotifierProviderChangeNotifierProvider- 识别: 定位相关逻辑。
- 转换: 重写为类或函数。
@riverpod - 替换: 更新使用者以使用生成的provider(例如,观察状态时使用而非
myProvider)。myProvider.notifier