名称: asyncredux-abort-dispatch 描述: 停止AsyncRedux(Flutter)动作的调度。仅在用户提到abortDispatch(),或明确要求在特定条件下中止或阻止调度时使用。
AsyncRedux 中止调度
什么是abortDispatch()?
abortDispatch()方法是ReduxAction上的一个可选方法,允许您条件性地防止动作执行。当此方法返回true时,整个动作将被跳过——before()、reduce()和after()不会运行,状态保持不变。
class MyAction extends ReduxAction<AppState> {
@override
bool abortDispatch() {
// 返回true以中止,false以继续
return someCondition;
}
@override
AppState? reduce() {
// 仅当abortDispatch()返回false时运行
return state.copy(/* ... */);
}
}
基本用法
最简单的用例是在允许动作继续之前检查条件:
class LoadUserProfile extends ReduxAction<AppState> {
@override
bool abortDispatch() => state.user == null;
@override
Future<AppState?> reduce() async {
// 仅当用户已登录时运行
final profile = await api.fetchProfile(state.user!.id);
return state.copy(profile: profile);
}
}
使用abortDispatch()的动作生命周期
当abortDispatch()返回true时,整个动作生命周期将被跳过:
class MyAction extends ReduxAction<AppState> {
@override
bool abortDispatch() => state.shouldSkip; // 如果为true:
@override
void before() {
// 中止时不调用
}
@override
AppState? reduce() {
// 中止时不调用
}
@override
void after() {
// 中止时不调用
}
}
这与在before()中抛出错误不同,后者仍会导致after()运行。
认证守卫模式
一个常见模式是创建一个需要认证的基动作:
/// 需要认证用户的基动作
abstract class AuthenticatedAction extends ReduxAction<AppState> {
@override
bool abortDispatch() => state.user == null;
}
/// 扩展此类的动作仅在用户登录时运行
class FetchUserOrders extends AuthenticatedAction {
@override
Future<AppState?> reduce() async {
// 安全使用state.user! - abortDispatch确保其不为null
final orders = await api.getOrders(state.user!.id);
return state.copy(orders: orders);
}
}
class UpdateUserSettings extends AuthenticatedAction {
final Settings newSettings;
UpdateUserSettings(this.newSettings);
@override
Future<AppState?> reduce() async {
await api.updateSettings(state.user!.id, newSettings);
return state.copy(settings: newSettings);
}
}
创建带有中止逻辑的基动作
您可以在基动作中组合多个中止条件:
abstract class AppAction extends ReduxAction<AppState> {
// 在子类中重写以添加动作特定的中止逻辑
bool shouldAbort() => false;
@override
bool abortDispatch() {
// 全局中止条件
if (state.isMaintenanceMode) return true;
if (state.isAppLocked) return true;
// 动作特定的中止条件
return shouldAbort();
}
}
class RefreshData extends AppAction {
@override
bool shouldAbort() {
// 如果数据仍新鲜,则不刷新
return state.lastRefresh != null &&
DateTime.now().difference(state.lastRefresh!) < Duration(minutes: 5);
}
@override
Future<AppState?> reduce() async {
final data = await api.fetchData();
return state.copy(data: data, lastRefresh: DateTime.now());
}
}
基于角色的授权
使用abortDispatch()实现基于角色的访问控制:
abstract class AdminAction extends ReduxAction<AppState> {
@override
bool abortDispatch() => state.user?.role != UserRole.admin;
}
class DeleteAllUsers extends AdminAction {
@override
Future<AppState?> reduce() async {
// 仅管理员可以执行此代码
await api.deleteAllUsers();
return state.copy(users: []);
}
}
条件功能动作
当功能被禁用时阻止动作:
class UsePremiumFeature extends ReduxAction<AppState> {
@override
bool abortDispatch() => !state.user!.isPremium;
@override
AppState? reduce() {
// 仅限高级用户的功能
return state.copy(/* ... */);
}
}
内置混合:AbortWhenNoInternet
AsyncRedux提供AbortWhenNoInternet,一个混合,当没有互联网连接时静默中止动作:
class FetchLatestNews extends AppAction with AbortWhenNoInternet {
@override
Future<AppState?> reduce() async {
// 仅当互联网可用时运行
final news = await api.fetchNews();
return state.copy(news: news);
}
}
AbortWhenNoInternet的关键特性:
- 不显示错误对话框
- 不抛出异常
- 动作被静默取消
- 仅检查设备互联网开关状态(不检查服务器可用性)
与CheckInternet相比,后者显示错误对话框而不是静默中止。
abortDispatch() 与在before()中抛出异常
根据用例选择正确方法:
| 方法 | after()运行? |
显示错误? | 何时使用 |
|---|---|---|---|
abortDispatch()返回true |
否 | 否 | 静默跳过动作 |
在before()中抛出异常 |
是 | 是(如果是UserException) | 向用户显示错误 |
// 静默中止 - 用户不知道动作被跳过
class SilentRefresh extends ReduxAction<AppState> {
@override
bool abortDispatch() => state.isOffline;
// ...
}
// 可见错误 - 用户看到消息
class ExplicitRefresh extends ReduxAction<AppState> {
@override
void before() {
if (state.isOffline) {
throw UserException('离线时无法刷新');
}
}
// ...
}
何时使用abortDispatch()
好的使用场景:
- 认证守卫(动作需要登录用户)
- 授权检查(动作需要特定角色/权限)
- 功能标志(仅限高级用户)
- 新鲜度检查(如果数据最近,则不重新获取)
- 维护模式(全局禁用某些动作)
- 幂等性(如果动作效果已应用,则跳过)
考虑替代方案时:
- 您希望用户看到错误消息(在
before()中抛出UserException) - 需要运行清理代码(使用
before()+after()模式) - 实现速率限制(使用
Throttle或Debounce混合) - 防止重复调度(使用
NonReentrant混合)
完整示例
// 带有常见中止逻辑的基动作
abstract class AppAction extends ReduxAction<AppState> {
@override
bool abortDispatch() {
// 全局维护模式检查
if (state.maintenanceMode) return true;
return false;
}
}
// 认证动作,同时检查维护模式
abstract class AuthenticatedAction extends AppAction {
@override
bool abortDispatch() {
// 首先检查父条件
if (super.abortDispatch()) return true;
// 然后检查认证
return state.currentUser == null;
}
}
// 管理员动作,带有完整授权链
abstract class AdminAction extends AuthenticatedAction {
@override
bool abortDispatch() {
if (super.abortDispatch()) return true;
return state.currentUser?.role != UserRole.admin;
}
}
// 使用层次结构的具体动作
class BanUser extends AdminAction {
final String userId;
BanUser(this.userId);
@override
Future<AppState?> reduce() async {
// 仅当以下条件满足时才到达这里:
// 1. 不在维护模式
// 2. 用户已登录
// 3. 用户是管理员
await api.banUser(userId);
return state.copy(
users: state.users.where((u) => u.id != userId).toList(),
);
}
}
重要注意事项
abortDispatch()在before()、reduce()和after()之前检查- 中止时,不会发生状态更改
- 动作被静默跳过——默认不抛出或记录错误
- 谨慎使用此功能;文档警告它是一个“强大功能”,仅当您“确定它是正确解决方案”时才使用
参考文献
文档URL:
- https://asyncredux.com/flutter/advanced-actions/aborting-the-dispatch
- https://asyncredux.com/flutter/advanced-actions/redux-action
- https://asyncredux.com/flutter/advanced-actions/before-and-after-the-reducer
- https://asyncredux.com/flutter/advanced-actions/action-status
- https://asyncredux.com/flutter/advanced-actions/control-mixins
- https://asyncredux.com/flutter/advanced-actions/internet-mixins
- https://asyncredux.com/flutter/advanced-actions/action-mixins
- https://asyncredux.com/flutter/basics/actions-and-reducers
- https://asyncredux.com/flutter/basics/action-simplification