当点击网页上的返回按钮时,Riverpod会给出一个坏状态异常



当有人点击StateNotifiers网页上的后退按钮时,我的StateNotifier中出现了这个错误。我已经将其隔离到下面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);
}
}

我相信您可以通过检查mounted来解决这个问题,然后在API调用后设置状态,如:

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作者的奇迹示例项目中的一个很好的例子可以在这里找到。

最新更新