flowr-usage
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFlowR Usage
FlowR 使用指南
Use FlowR APIs correctly without assuming a specific project file layout.
无需依赖特定项目文件结构,正确使用FlowR API。
First Checks
初始检查
- Follow the project : this repository uses
AGENTS.mdfor Flutter and Dart commands, for examplefvmandfvm dart test.fvm flutter analyze - Before editing code, run . If unrelated uncommitted changes exist, ask whether to commit or ignore them.
git status --short - Prefer the project's existing architecture. This skill covers FlowR API usage, not where files must live.
- 遵循项目的文档:本仓库使用
AGENTS.md执行Flutter和Dart命令,例如fvm和fvm dart test。fvm flutter analyze - 编辑代码前,运行。若存在无关的未提交变更,询问是否提交或忽略。
git status --short - 优先遵循项目现有架构。本指南仅覆盖FlowR API的使用方式,不规定文件存放位置。
Imports
导入规则
- Pure Dart code: import .
package:flowr_dart/flowr_dart.dart - Flutter MVVM code: import .
package:flowr/flowr_mvvm.dart - Import when public methods use
dart:async,FutureOr, orStreamtypes directly.StreamSubscription - Do not import or
flowr/src/...from application code.flowr_dart/src/...
- 纯Dart代码:导入。
package:flowr_dart/flowr_dart.dart - Flutter MVVM代码:导入。
package:flowr/flowr_mvvm.dart - 当公共方法直接使用、
FutureOr或Stream类型时,导入StreamSubscription。dart:async - 应用代码中禁止导入或
flowr/src/...。flowr_dart/src/...
flowr_dart Core
flowr_dart 核心用法
Use for method-driven state:
FlowR<T>dart
class Counter extends FlowR<int> {
Counter() : super(0);
int increment() => put(value + 1);
}Use when the next state depends on the current state and may fail:
updatedart
FutureOr<UserState?> refresh() => update(
(old) async => old.copyWith(user: await api.loadUser()),
onError: (error, stackTrace) => putError(error, stackTrace),
);Use for event-driven state:
FlowB<E, S>dart
sealed class CounterEvent {
const CounterEvent();
}
class CounterIncremented extends CounterEvent {
const CounterIncremented();
}
class CounterBloc extends FlowB<CounterEvent, int> {
CounterBloc() : super(0) {
on<CounterIncremented>((event, emit) => emit(state + 1));
}
}Rules:
- extends
FlowR<T>and exposesCubit<T>as the legacy name forvalue.state - extends
FlowB<E, S>and should be driven fromBloc<E, S>.add(event) - is protected/test-only style; public callers should dispatch events.
FlowB.put - and
put(value)follow bloc equality semantics: ifupdate(...), no stream event is emitted.newValue == currentValue - uses bloc-native semantics. It does not replay the current state to new subscribers; use
streamorvaluefor synchronous reads.state - Do not add overrides or compatibility switches to restore replayable streams.
valueStream - is kept for legacy FlowR APIs; bloc-native code may use
dispose().close()
使用实现方法驱动的状态管理:
FlowR<T>dart
class Counter extends FlowR<int> {
Counter() : super(0);
int increment() => put(value + 1);
}当下一状态依赖当前状态且可能执行失败时,使用:
updatedart
FutureOr<UserState?> refresh() => update(
(old) async => old.copyWith(user: await api.loadUser()),
onError: (error, stackTrace) => putError(error, stackTrace),
);使用实现事件驱动的状态管理:
FlowB<E, S>dart
sealed class CounterEvent {
const CounterEvent();
}
class CounterIncremented extends CounterEvent {
const CounterIncremented();
}
class CounterBloc extends FlowB<CounterEvent, int> {
CounterBloc() : super(0) {
on<CounterIncremented>((event, emit) => emit(state + 1));
}
}规则说明:
- 继承自
FlowR<T>,并保留Cubit<T>作为value的兼容命名。state - 继承自
FlowB<E, S>,应通过Bloc<E, S>触发状态变更。add(event) - 为受保护/仅测试用方法;外部调用者应通过分发事件触发。
FlowB.put - 和
put(value)遵循Bloc的相等性语义:若update(...),则不会发送流事件。newValue == currentValue - 使用Bloc原生语义,不会向新订阅者重放当前状态;同步读取状态请使用
stream或value。state - 请勿添加重写或兼容开关来恢复可重放流。
valueStream - 为FlowR遗留API;Bloc原生代码可使用
dispose()。close()
State Rules
状态管理规则
- Prefer immutable state: fields,
finalconstructors,const, and value equality when the project already uses it.copyWith - To trigger a UI update, return a new unequal model instance.
- For ,
List, andMapfields, allocate a new collection before emitting:Set
dart
update((old) => old.copyWith(items: [...old.items, item]));- Do not mutate an existing state object and call .
put(old) - Use or
skpNull(value, 'name')to cancel a flow without treating it as a failure.skpIf(condition, 'reason') - If a breaking-change compatibility setting is requested, explicitly tell the user what behavior changed and why. Do not hide it behind config.
- 优先使用不可变状态:字段、
final构造方法、const方法,以及项目已采用的值相等性判断。copyWith - 若要触发UI更新,需返回一个不相等的新模型实例。
- 对于、
List和Map类型的字段,在发送状态前需分配新的集合:Set
dart
update((old) => old.copyWith(items: [...old.items, item]));- 请勿修改现有状态对象后调用。
put(old) - 使用或
skpNull(value, 'name')来终止流程,且不将其视为失败。skpIf(condition, 'reason') - 若需要启用破坏性变更的兼容设置,请明确告知用户行为变更的内容及原因,不要隐藏在配置背后。
Stream Helpers
流工具用法
Use normal helpers on and :
Stream<T>FlowR.streamFlowB.streamdart
final labels = counter.stream.distinctWith((count) => 'count: $count');
final evenValues = counter.stream.where((count) => count.isEven);
final uniqueValues = counter.stream.distinctUnique();- filters consecutive events by a selected key.
distinctBy((event) => event.field) - maps then de-duplicates consecutive mapped values.
distinctWith((event) => mapped) - filters duplicates across the whole stream history.
distinctUnique() - Legacy helpers such as
ValueStreamandmapValueare only for actualwhereValueinstances, not FlowR view-model streams.ValueStream<T>
在和上使用标准工具:
FlowR.streamFlowB.streamStream<T>dart
final labels = counter.stream.distinctWith((count) => 'count: $count');
final evenValues = counter.stream.where((count) => count.isEven);
final uniqueValues = counter.stream.distinctUnique();- 根据选定的键过滤连续重复的事件。
distinctBy((event) => event.field) - 先映射事件,再过滤连续重复的映射值。
distinctWith((event) => mapped) - 过滤整个流历史中的重复值。
distinctUnique() - 遗留的工具(如
ValueStream和mapValue)仅适用于实际的whereValue实例,不适用于FlowR视图模型流。ValueStream<T>
flowr Flutter Usage
flowr Flutter 用法
Define models as -compatible immutable objects. Use
for method-driven Flutter state:
FrModelFrViewModel<M>dart
class CounterModel {
final int value;
const CounterModel({this.value = 0});
CounterModel copyWith({int? value}) =>
CounterModel(value: value ?? this.value);
}
class CounterViewModel extends FrViewModel<CounterModel> {
CounterViewModel() : super(const CounterModel());
FutureOr<CounterModel?> increment() =>
update((old) => old.copyWith(value: old.value + 1));
}Use when callers naturally dispatch events:
FrBlocViewModel<E, M>dart
class CounterViewModel
extends FrBlocViewModel<CounterEvent, CounterModel> {
CounterViewModel() : super(const CounterModel()) {
on<CounterIncremented>(
(event, emit) => emit(state.copyWith(value: state.value + 1)),
);
}
}Register ownership with :
FrProviderdart
FrProvider(
(context) => CounterViewModel(),
child: const CounterPage(),
);- Use for GetIt-created instances that should be pulled into the widget tree.
FrProvider.di - Use for an existing instance, such as dialog/subtree reuse.
FrProvider.value - Use for multiple providers.
FrProvider.multi - disposes
FrProviderand closes blocDisposeMxinstances.Closable
Build UI with:
dart
FrView<CounterViewModel, CounterModel>(
builder: (context, snap, child) => Text('${snap.data.value}'),
);- rebuilds from state.
FrView - handles side effects.
FrListener - combines listener and builder.
FrConsumer - groups listeners.
FrMultiListener - is a record:
FrSnap.(vm: VM, data: M) - ,
FrView,FrListener, andFrConsumerroute view models through bloc-native UI components.FrViewU
将模型定义为兼容的不可变对象。使用实现方法驱动的Flutter状态管理:
FrModelFrViewModel<M>dart
class CounterModel {
final int value;
const CounterModel({this.value = 0});
CounterModel copyWith({int? value}) =>
CounterModel(value: value ?? this.value);
}
class CounterViewModel extends FrViewModel<CounterModel> {
CounterViewModel() : super(const CounterModel());
FutureOr<CounterModel?> increment() =>
update((old) => old.copyWith(value: old.value + 1));
}当调用者自然需要分发事件时,使用:
FrBlocViewModel<E, M>dart
class CounterViewModel
extends FrBlocViewModel<CounterEvent, CounterModel> {
CounterViewModel() : super(const CounterModel()) {
on<CounterIncremented>(
(event, emit) => emit(state.copyWith(value: state.value + 1)),
);
}
}通过注册实例所有权:
FrProviderdart
FrProvider(
(context) => CounterViewModel(),
child: const CounterPage(),
);- 使用将GetIt创建的实例引入组件树。
FrProvider.di - 使用复用现有实例,例如对话框/子树场景。
FrProvider.value - 使用注册多个提供者。
FrProvider.multi - 会自动释放
FrProvider实例并关闭Bloc的DisposeMx实例。Closable
构建UI的方式:
dart
FrView<CounterViewModel, CounterModel>(
builder: (context, snap, child) => Text('${snap.data.value}'),
);- 会根据状态变化重建UI。
FrView - 处理副作用。
FrListener - 结合了监听器和构建器的功能。
FrConsumer - 用于分组管理多个监听器。
FrMultiListener - 是一个记录类型:
FrSnap。(vm: VM, data: M) - 、
FrView、FrListener和FrConsumer通过Bloc原生UI组件传递视图模型。FrViewU
FrUnion
FrUnion 用法
Use for small global typed state sets:
FrUnionViewModeldart
FrConfig.initialize(
frUnion: FrUnion.of({CounterModel(), UserModel()}),
);- accepts plain model values.
FrUnion.of({...}) - or
FrUnion.ofTaggedModel({(model, 'tag')})supports multiple values of the same type.FrUnionViewModel.ofTag(...) - Read typed values with or
FrViewU<M>.vm.streamBy<M>(tag: ...) - Update typed values with .
vm.updateBy<M>((old) => next, tag: ...) - Avoid a single global for complex app domains with unclear ownership.
FrUnionViewModel
使用管理小型全局类型化状态集合:
FrUnionViewModeldart
FrConfig.initialize(
frUnion: FrUnion.of({CounterModel(), UserModel()}),
);- 接受普通模型值。
FrUnion.of({...}) - 或
FrUnion.ofTaggedModel({(model, 'tag')})支持同一类型的多个值。FrUnionViewModel.ofTag(...) - 使用或
FrViewU<M>读取类型化值。vm.streamBy<M>(tag: ...) - 使用更新类型化值。
vm.updateBy<M>((old) => next, tag: ...) - 避免为复杂应用域使用单一全局,以免所有权模糊。
FrUnionViewModel
References
参考文档
Load these only when the request touches the package or scenario:
- : environment selector package usage.
references/fr-mvvm-env.md - : locale state and locale switcher usage.
references/fr-mvvm-locale.md - : theme switching, ThemeExtension helpers, built-in and JSON-config theme sources, and image scheme usage.
references/fr-mvvm-theme.md - : user selector/session state package usage.
references/fr-mvvm-user.md - : detailed migration after FlowR breaking changes.
references/migration.md
仅当请求涉及对应包或场景时,加载以下文档:
- :环境选择器包的使用指南。
references/fr-mvvm-env.md - :Locale状态及语言切换器的使用指南。
references/fr-mvvm-locale.md - :主题切换、ThemeExtension工具、内置及JSON配置主题源,以及图片方案的使用指南。
references/fr-mvvm-theme.md - :用户选择器/会话状态包的使用指南。
references/fr-mvvm-user.md - :FlowR破坏性变更后的详细迁移指南。
references/migration.md
Validation
验证步骤
- Format changed Dart files with .
fvm dart format <paths> - For pure Dart package code, run or focused tests.
fvm dart test - For Flutter package/app code, run for touched widgets or providers.
fvm flutter test - Run or
fvm dart analyzewhen shared APIs or package surfaces change.fvm flutter analyze
- 使用格式化修改后的Dart文件。
fvm dart format <paths> - 对于纯Dart包代码,运行或指定测试用例。
fvm dart test - 对于Flutter包/应用代码,运行测试修改的组件或提供者。
fvm flutter test - 当共享API或包表面发生变更时,运行或
fvm dart analyze。fvm flutter analyze