feat: add support for keepPreviousData & examples regarding this

This commit is contained in:
Kingkor Roy Tirtho
2022-08-07 10:54:28 +06:00
parent 4d6d1a1648
commit 462a7042fa
13 changed files with 294 additions and 64 deletions
+62 -8
View File
@@ -72,6 +72,8 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
Connectivity _connectivity;
T? _previousData;
Query({
required this.queryKey,
required this.task,
@@ -85,6 +87,7 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
this.refetchOnReconnect,
this.refetchInterval,
this.enabled = true,
T? previousData,
Connectivity? connectivity,
T? initialData,
QueryListener<T>? onData,
@@ -92,9 +95,10 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
}) : _staleTime = staleTime,
_initialData = initialData,
_externalData = externalData,
status = QueryStatus.idle,
status = previousData == null ? QueryStatus.idle : QueryStatus.success,
_connectivity = connectivity ?? Connectivity(),
super(data: initialData) {
_previousData = previousData,
super(data: previousData ?? initialData) {
if (onData != null) _onDataListeners.add(onData);
if (onError != null) _onErrorListeners.add(onError);
@@ -107,6 +111,7 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
QueryJob<T, Outside> options, {
required super.queryBowl,
required Outside externalData,
T? previousData,
QueryListener<T>? onData,
QueryListener<dynamic>? onError,
}) : queryKey = options.queryKey,
@@ -118,13 +123,14 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
refetchInterval = options.refetchInterval,
refetchOnMount = options.refetchOnMount,
refetchOnReconnect = options.refetchOnReconnect,
status = QueryStatus.idle,
status = previousData == null ? QueryStatus.idle : QueryStatus.success,
_connectivity = options.connectivity ?? Connectivity(),
_previousData = previousData,
super(
cacheTime: options.cacheTime ?? const Duration(minutes: 5),
retries: options.retries ?? 3,
retryDelay: options.retryDelay ?? const Duration(milliseconds: 200),
data: options.initialData,
data: previousData ?? options.initialData,
) {
if (onData != null) _onDataListeners.add(onData);
if (onError != null) _onErrorListeners.add(onError);
@@ -222,12 +228,20 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
_onErrorListeners.remove(listener);
}
/// fetches data or runs the provided task initially
///
/// Once [data] is available it won't run the [task] ever again
/// and will only return the available data
///
/// If a [fetch] is already running in the background it'll just return
/// the current available [data] (which can be nul if no [initialData]
/// was provided) instead of running the task to prevent race conditions
Future<T?> fetch() async {
if (!enabled) return null;
/// if isLoading/isRefetching is true that means its already fetching/
/// refetching. So [_execute] again can create a race condition
if (isLoading || isRefetching || hasData) return data;
if (isLoading || isRefetching || (hasData && !isPreviousData)) return data;
status = QueryStatus.loading;
notifyListeners();
return _execute().then((_) {
@@ -236,6 +250,18 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
});
}
/// refetches a valid or invalid [Query]
///
/// When called before calling [fetch] in a [Query] it'll
/// automatically run [fetch]
///
/// But if it's used to fetch the first data of a non-enabled [Query]
/// aka `LazyQuery`, it'll execute the task & will set the status
/// `enabled=true`
///
/// If a [refetch] is already running in the background it'll just return
/// the current available [data] instead of running the task to prevent
/// race conditions
Future<T?> refetch() async {
/// if isLoading/isRefetching is true that means its already fetching/
/// refetching. So [_execute] again can create a race condition
@@ -266,14 +292,22 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
notifyListeners();
}
/// Sets the [externalData] from outside of the query
///
/// Remember, it's for the very instance of [Query]
/// So this won't persist through later UI/[Query] updates
void setExternalData(Outside externalData) {
_prevUsedExternalData = _externalData;
_externalData = externalData;
}
/// Resets the query
///
/// The values of internal state of the query are reset to the
/// initial ones
void reset() {
refetchCount = 0;
data = _initialData;
data = _previousData ?? _initialData;
error = null;
fetched = false;
status = QueryStatus.idle;
@@ -283,8 +317,12 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
mounts.clear();
}
/// Update configurations of the query after already creating the Query
/// instance
/// Update configurations of the query
/// after already creating the Query instance
///
/// Remember, it's just for the single query instance
/// In the next UI update/render the options will get reset
/// to the default ones defined in the [QueryJob] or [QueryBowlScope]
void updateDefaultOptions({
Duration? refetchInterval,
Duration? staleTime,
@@ -310,11 +348,20 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
notifyListeners();
}
/// checks if the application is connected to internet in any mean
///
/// It's true when any one this is connected -
/// - ethernet
/// - mobile
/// - wifi
Future<bool> isInternetConnected() async {
return isConnectedToInternet(await _connectivity.checkConnectivity());
}
/// invalidates the query
///
/// Forcefully makes the query stale & expired which results in a refetch
/// when met conditions
void invalidate() {
/// subtracting [staleTime] from [updatedAt] as staleTime=Duration.zero
/// indicates the query must never become stale but subtracting the
@@ -340,6 +387,9 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
bool get isLoading => status == QueryStatus.loading;
bool get isRefetching => status == QueryStatus.refetching;
bool get isSuccess => status == QueryStatus.success;
bool get isPreviousData {
return _previousData != null ? _previousData == data : false;
}
A? cast<A>() => this is A ? this as A : null;
@@ -348,6 +398,10 @@ class Query<T extends Object, Outside> extends BaseOperation<T> {
@override
void mount(ValueKey<String> uKey) {
super.mount(uKey);
/// refetching on mount if it's set to true
/// also checking if the is stale or not
/// no need to refetch a valid query for no reason
if (refetchOnMount == true && isStale) {
this.isInternetConnected().then((isConnected) async {
if (isConnected) await refetch();