问题描述
当人们点击他们网页上的后退按钮时,我在我的 StateNotifiers 中收到此错误。我已将其隔离到 longRunningAPI
请求位于下方的位置。
Exception has occurred.
"Error: Bad state: Tried to use RunListNotifier after `dispose` was called.
final runListController = StateNotifierProvider.autodispose
.family<RunListNotifier,AsyncValue<List<Run>>,RunListParameter>(
(ref,param) {
return RunListNotifier(read: ref.read,param: param);
});
class RunListNotifier extends StateNotifier<AsyncValue<List<Run>>> {
RunListNotifier({required this.read,required this.param})
: super(AsyncLoading()) {
fetchViaAPI(param);
}
final Reader read;
final RunListParameter param;
void fetchViaAPI(RunListParameter param) async {
state = AsyncLoading();
try {
List<Run> stuff = await read(apiProvider).longRunningAPI(param: param);
state = AsyncData(stuff);
} catch (e) {
state = AsyncError(e);
}
}
}
在捕获中简单地做这样的事情是否安全?
} catch (e) {
if (e.runtimeType.toString() == 'StateError') {
// ignore the error
} else {
state = AsyncError(e);
}
}
解决方法
我相信您可以通过在 API 调用后设置状态之前检查 mounted
来解决此问题,如下所示:
List<Run> stuff = await read(apiProvider).longRunningAPI(param: param);
if (!mounted) return;
state = AsyncData(stuff);
这只是检查是否调用了 dispose,如果是,则不要尝试修改状态。
另一个可能有用的资源是将 cancelToken
添加到您的 API 调用并在提供者被释放时取消。
final longRunningApi = FutureProvider.autoDispose.family<List<Run>,RunListParameter>((ref,param) async {
final cancelToken = CancelToken();
ref.onDispose(cancelToken.cancel);
final api = await ref.watch(apiProvider);
final res = await api.longRunningApi(param,cancelToken);
ref.maintainState = true;
return res;
});
然后您必须将 cancelToken 添加到您的实际请求中。在 Riverpod 的作者的 marvel example project 中可以找到一个很好的例子here。