Cancellation
CancelToken is a one-shot cooperative cancellation signal. Pass it to fetchQuery, watchQuery, or prefetch and call cancel() to abort the fetch before start or during execution.
Creating a Token
final token = CancelToken();
A token can only be cancelled once. Calling cancel() a second time is a no-op.
Cancelling a fetchQuery
final token = CancelToken();
// Start the fetch
final future = client.fetchQuery<User>(
key: ['users', userId],
fetcher: () => api.getUser(userId),
cancelToken: token,
);
// Cancel it (e.g. the user navigated away)
token.cancel();
try {
final user = await future;
} on QoraCancelException catch (e) {
// e.key is the string-encoded query key
print('Fetch cancelled: ${e.key}');
}
When cancelled, fetchQuery throws QoraCancelException to the caller and restores the cache entry to its pre-fetch snapshot (no partial state is left behind).
Cancelling a watchQuery stream
final token = CancelToken();
final sub = client.watchQuery<User>(
key: ['users', userId],
fetcher: () => api.getUser(userId),
cancelToken: token,
).listen((state) { ... });
// On widget dispose: cancel the in-flight fetch
token.cancel();
await sub.cancel();
token.cancel() aborts the HTTP request; sub.cancel() removes the state listener. Do both on dispose for a clean teardown.Timeout Pattern
Combine CancelToken with Future.delayed to implement a request timeout:
Future<User> fetchWithTimeout(int userId, Duration timeout) async {
final token = CancelToken();
Timer(timeout, token.cancel);
try {
return await client.fetchQuery<User>(
key: ['users', userId],
fetcher: () => api.getUser(userId),
cancelToken: token,
);
} on QoraCancelException {
throw TimeoutException('User fetch timed out after $timeout');
}
}
Navigation Cancellation in Flutter
In a StatefulWidget, tie the token to the widget lifecycle:
class _UserScreenState extends State<UserScreen> {
CancelToken? _fetchToken;
Future<void> _loadUser() async {
_fetchToken = CancelToken();
try {
await context.qora.fetchQuery<User>(
key: ['users', widget.userId],
fetcher: () => api.getUser(widget.userId),
cancelToken: _fetchToken,
);
} on QoraCancelException {
// Widget disposed: ignore
}
}
@override
void dispose() {
_fetchToken?.cancel();
super.dispose();
}
}
CancelToken API
Constructor
CancelToken()
Properties
| Property | Type | Description |
|---|---|---|
isCancelled | bool | true after cancel() is called. |
Methods
| Method | Signature | Description |
|---|---|---|
cancel() | void | Mark the token as cancelled. Idempotent and safe to call multiple times. |
QoraCancelException
Thrown by fetchQuery and prefetch when a fetch is cancelled via CancelToken.
class QoraCancelException implements Exception {
final String key; // JSON-encoded normalised query key
}
| Property | Type | Description |
|---|---|---|
key | String | The string-encoded query key, e.g. '["users",1]' |
Tracker Hook
QoraTracker.onQueryCancelled(String key) is called every time a fetch is cancelled via CancelToken. Implement it on your custom tracker to log or measure cancellation rates:
class AnalyticsTracker extends NoOpTracker {
@override
void onQueryCancelled(String key) {
analytics.track('query_cancelled', {'key': key});
}
}
Related
- QoraClient API:
fetchQuery,watchQuery,prefetchsignatures - QoraTracker: Observability hooks