diff --git a/packages/fl_query/lib/src/core/client.dart b/packages/fl_query/lib/src/core/client.dart index fe1bc50..030a64f 100644 --- a/packages/fl_query/lib/src/core/client.dart +++ b/packages/fl_query/lib/src/core/client.dart @@ -110,6 +110,7 @@ class QueryClient { ) .cast(); query.updateQueryFn(queryFn); + query.updateNextPageFn(nextPage); cache.addInfiniteQuery(query); return query; } diff --git a/packages/fl_query/lib/src/core/infinite_query.dart b/packages/fl_query/lib/src/core/infinite_query.dart index fd99676..cdc83a2 100644 --- a/packages/fl_query/lib/src/core/infinite_query.dart +++ b/packages/fl_query/lib/src/core/infinite_query.dart @@ -314,6 +314,7 @@ class InfiniteQuery } void updateNextPageFn(InfiniteQueryNextPage nextPage) { + if (state._nextPage == nextPage) return; state = state.copyWith(nextPage: nextPage); } diff --git a/packages/fl_query_hooks/example/macos/Flutter/GeneratedPluginRegistrant.swift b/packages/fl_query_hooks/example/macos/Flutter/GeneratedPluginRegistrant.swift index 37d4dc4..e777c67 100644 --- a/packages/fl_query_hooks/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/packages/fl_query_hooks/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,8 @@ import FlutterMacOS import Foundation -import connectivity_plus_macos import path_provider_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) } diff --git a/packages/fl_query_hooks/example/windows/flutter/generated_plugin_registrant.cc b/packages/fl_query_hooks/example/windows/flutter/generated_plugin_registrant.cc index 8083d74..8b6d468 100644 --- a/packages/fl_query_hooks/example/windows/flutter/generated_plugin_registrant.cc +++ b/packages/fl_query_hooks/example/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,6 @@ #include "generated_plugin_registrant.h" -#include void RegisterPlugins(flutter::PluginRegistry* registry) { - ConnectivityPlusWindowsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); } diff --git a/packages/fl_query_hooks/example/windows/flutter/generated_plugins.cmake b/packages/fl_query_hooks/example/windows/flutter/generated_plugins.cmake index 8cf5d42..b93c4c3 100644 --- a/packages/fl_query_hooks/example/windows/flutter/generated_plugins.cmake +++ b/packages/fl_query_hooks/example/windows/flutter/generated_plugins.cmake @@ -3,7 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - connectivity_plus_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/packages/fl_query_hooks/lib/src/use_infinite_query.dart b/packages/fl_query_hooks/lib/src/use_infinite_query.dart index 356ad57..1a5f012 100644 --- a/packages/fl_query_hooks/lib/src/use_infinite_query.dart +++ b/packages/fl_query_hooks/lib/src/use_infinite_query.dart @@ -1,8 +1,9 @@ import 'dart:async'; import 'package:fl_query/fl_query.dart'; +import 'package:fl_query_hooks/src/use_query_client.dart'; +import 'package:fl_query_hooks/src/utils/use_updater.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/src/foundation/diagnostics.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; InfiniteQuery @@ -19,202 +20,60 @@ InfiniteQuery bool enabled = true, List? keys, }) { - return use(UseInfiniteQuery( - queryKey, - queryFn, - nextPage: nextPage, - initialPage: initialPage, - retryConfig: retryConfig, - refreshConfig: refreshConfig, - jsonConfig: jsonConfig, - onData: onData, - onError: onError, - enabled: enabled, - keys: keys, - )); -} - -class UseInfiniteQuery - extends Hook> { - final InfiniteQueryFn queryFn; - final String queryKey; - - final PageType initialPage; - final InfiniteQueryNextPage nextPage; - - final RetryConfig retryConfig; - final RefreshConfig refreshConfig; - final JsonConfig? jsonConfig; - - final ValueChanged>? onData; - final ValueChanged>? onError; - - // widget specific - final bool enabled; - - const UseInfiniteQuery( - this.queryKey, - this.queryFn, { - required this.nextPage, - required this.initialPage, - this.retryConfig = DefaultConstants.retryConfig, - this.refreshConfig = DefaultConstants.refreshConfig, - this.jsonConfig, - this.onData, - this.onError, - this.enabled = true, - super.keys, - }) : assert( - (jsonConfig != null && enabled) || jsonConfig == null, - 'jsonConfig is only supported when enabled is true', - ); - - @override - createState() => _UseInfiniteQueryState(); -} - -class _UseInfiniteQueryState extends HookState< - InfiniteQuery, - UseInfiniteQuery> { - InfiniteQuery? query; - - VoidCallback? removeListener; - - StreamSubscription>? dataSubscription; - StreamSubscription>? errorSubscription; - - void rebuild([_]) { - setState(() {}); - } - - Future initialize() async { - setState(() { - _createQuery(); - - if (hook.onData != null) - dataSubscription = query!.dataStream.listen(hook.onData); - if (hook.onError != null) - errorSubscription = query!.errorStream.listen(hook.onError); - - removeListener = query!.addListener(rebuild); - }); - if (hook.enabled) { - await query!.fetch(); - } - } - - void _createQuery() { - query = QueryClient.of(context).createInfiniteQuery( - hook.queryKey, - hook.queryFn, - initialParam: hook.initialPage, - nextPage: hook.nextPage, - retryConfig: hook.retryConfig, - refreshConfig: hook.refreshConfig, - jsonConfig: hook.jsonConfig, + final rebuild = useUpdater(); + final client = useQueryClient(); + final query = useMemoized(() { + return client.createInfiniteQuery( + queryKey, + queryFn, + initialParam: initialPage, + nextPage: nextPage, + jsonConfig: jsonConfig, + refreshConfig: refreshConfig, + retryConfig: retryConfig, ); - } + }, [client, queryKey]); - @override - void initHook() { - super.initHook(); - WidgetsBinding.instance.addPostFrameCallback((_) { - initialize(); - }); - } + useEffect(() { + return query.addListener(rebuild); + }, [query]); - @override - void dispose() { - dataSubscription?.cancel(); - errorSubscription?.cancel(); - removeListener?.call(); - super.dispose(); - } + useEffect( + () { + if (enabled) { + query.fetch(); + } + return null; + }, + [enabled], + ); - @override - void didUpdateHook(oldHook) { - super.didUpdateHook(oldHook); + useEffect(() { + query.updateQueryFn(queryFn); + return null; + }, [queryFn, query]); - if (oldHook.queryKey != hook.queryKey) { + useEffect(() { + query.updateNextPageFn(nextPage); + return null; + }, [nextPage, query]); + + useEffect(() { + StreamSubscription>? dataSubscription; + StreamSubscription>? errorSubscription; + + if (onData != null) { + dataSubscription = query.dataStream.listen(onData); + } + if (onError != null) { + errorSubscription = query.errorStream.listen(onError); + } + + return () { dataSubscription?.cancel(); errorSubscription?.cancel(); - removeListener?.call(); - initialize(); - return; - } else if (oldHook.enabled != hook.enabled && hook.enabled) { - query!.fetch(); - } - if (oldHook.queryFn != hook.queryFn) { - query!.updateQueryFn(hook.queryFn); - } - if (oldHook.nextPage != hook.nextPage) { - query!.updateNextPageFn(hook.nextPage); - } - if (oldHook.onData != hook.onData) { - dataSubscription?.cancel(); - if (hook.onData != null) - dataSubscription = query!.dataStream.listen(hook.onData); - } - if (oldHook.onError != hook.onError) { - errorSubscription?.cancel(); - if (hook.onError != null) - errorSubscription = query!.errorStream.listen(hook.onError); - } - } + }; + }, [onData, onError, query]); - @override - build(BuildContext context) { - if (query == null) { - _createQuery(); - } - return query!; - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty>( - 'queryFn', - hook.queryFn, - )); - properties - .add(DiagnosticsProperty>( - 'nextPage', - hook.nextPage, - )); - properties.add(DiagnosticsProperty( - 'initialPage', - hook.initialPage, - )); - properties.add(DiagnosticsProperty( - 'retryConfig', - hook.retryConfig, - )); - properties.add(DiagnosticsProperty( - 'refreshConfig', - hook.refreshConfig, - )); - properties.add(DiagnosticsProperty>( - 'jsonConfig', - hook.jsonConfig, - )); - properties - .add(DiagnosticsProperty>>( - 'onData', - hook.onData, - )); - properties - .add(DiagnosticsProperty>>( - 'onError', - hook.onError, - )); - properties.add(DiagnosticsProperty( - 'enabled', - hook.enabled, - )); - properties.add(DiagnosticsProperty( - 'queryKey', - hook.queryKey, - )); - } + return query; } diff --git a/packages/fl_query_hooks/lib/src/use_mutation.dart b/packages/fl_query_hooks/lib/src/use_mutation.dart index aba4f5c..7db8fa7 100644 --- a/packages/fl_query_hooks/lib/src/use_mutation.dart +++ b/packages/fl_query_hooks/lib/src/use_mutation.dart @@ -1,8 +1,8 @@ import 'dart:async'; import 'package:fl_query/fl_query.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/src/foundation/diagnostics.dart'; +import 'package:fl_query_hooks/src/use_query_client.dart'; +import 'package:fl_query_hooks/src/utils/use_updater.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; Mutation @@ -17,227 +17,64 @@ Mutation List? refreshInfiniteQueries, List? keys, }) { - return use( - UseMutation( + final rebuild = useUpdater(); + final client = useQueryClient(); + final mutation = useMemoized(() { + return client.createMutation( mutationKey, mutationFn, retryConfig: retryConfig, - onData: onData, - onError: onError, - onMutate: onMutate, - refreshQueries: refreshQueries, - refreshInfiniteQueries: refreshInfiniteQueries, - keys: keys, - ), - ); -} - -class UseMutation - extends Hook> { - final MutationFn mutationFn; - final String mutationKey; - - final RetryConfig retryConfig; - - final MutationOnDataFn? onData; - final MutationOnErrorFn? onError; - final MutationOnMutationFn? onMutate; - - // hook specific - final List? refreshQueries; - final List? refreshInfiniteQueries; - - const UseMutation( - this.mutationKey, - this.mutationFn, { - this.retryConfig = DefaultConstants.retryConfig, - this.onData, - this.onError, - this.onMutate, - this.refreshQueries, - this.refreshInfiniteQueries, - super.keys, - }); - - @override - createState() => - _UseMutationState(); -} - -class _UseMutationState - extends HookState, - UseMutation> { - Mutation? mutation; - - VoidCallback? removeListener; - - StreamSubscription? mutationSubscription; - StreamSubscription? dataSubscription; - StreamSubscription? errorSubscription; - - RecoveryType? recoveryData; - - void rebuild([_]) { - setState(() {}); - } - - void subscribeOnMutate() { - if (hook.onMutate != null) - mutationSubscription = mutation!.mutationStream.listen( - (event) async { - recoveryData = await hook.onMutate?.call(event); - - if (hook.onData != null) { - dataSubscription?.cancel(); - subscribeOnData(); - } - - if (hook.onError != null) { - errorSubscription?.cancel(); - subscribeOnError(); - } - }, - ); - } - - void subscribeOnData() { - if (hook.onData != null || - hook.refreshInfiniteQueries != null || - hook.refreshQueries != null) - dataSubscription = mutation!.dataStream.listen( - (event) { - final data = hook.onData?.call(event, recoveryData); - if (hook.refreshQueries != null) { - QueryClient.of(context).refreshQueries(hook.refreshQueries!); - } - if (hook.refreshInfiniteQueries != null) { - QueryClient.of(context) - .refreshInfiniteQueries(hook.refreshInfiniteQueries!); - } - return data; - }, - ); - } - - void subscribeOnError() { - if (hook.onError != null) - errorSubscription = mutation!.errorStream.listen( - (event) { - return hook.onError?.call(event, recoveryData); - }, - ); - } - - Future initialize() async { - setState(() { - _createMutation(); - subscribeOnMutate(); - subscribeOnData(); - subscribeOnError(); - removeListener = mutation!.addListener(rebuild); - }); - } - - void _createMutation() { - mutation = QueryClient.of(context).createMutation( - hook.mutationKey, - hook.mutationFn, - retryConfig: hook.retryConfig, ); - } + }, [client, mutationKey]); - @override - void initHook() { - super.initHook(); - WidgetsBinding.instance.addPostFrameCallback((_) async { - await initialize(); + final recoveryData = useState(null); + + useEffect(() { + return mutation.addListener(rebuild); + }, [mutation]); + + useEffect(() { + mutation.updateMutationFn(mutationFn); + return null; + }, [mutationFn, mutation]); + + useEffect(() { + if (onMutate != null) { + return mutation.mutationStream.listen((event) async { + recoveryData.value = await onMutate.call(event); + }).cancel; + } + return null; + }, [onMutate, mutation]); + + useEffect(() { + StreamSubscription? dataSubscription; + StreamSubscription? errorSubscription; + + dataSubscription = mutation.dataStream.listen((event) { + final data = onData?.call(event, recoveryData.value); + if (refreshQueries != null) { + client.refreshQueries(refreshQueries); + } + if (refreshInfiniteQueries != null) { + client.refreshInfiniteQueries(refreshInfiniteQueries); + } + return data; }); - } - @override - void dispose() { - mutationSubscription?.cancel(); - dataSubscription?.cancel(); - errorSubscription?.cancel(); - removeListener?.call(); - super.dispose(); - } + if (onError != null) { + errorSubscription = mutation.errorStream.listen( + (event) { + return onError(event, recoveryData.value); + }, + ); + } - @override - void didUpdateHook(oldHook) { - super.didUpdateHook(oldHook); - - if (oldHook.mutationKey != hook.mutationKey) { - mutationSubscription?.cancel(); + return () { dataSubscription?.cancel(); errorSubscription?.cancel(); - removeListener?.call(); - initialize(); - return; - } - if (oldHook.mutationFn != hook.mutationFn) { - mutation!.updateMutationFn(hook.mutationFn); - } - if (oldHook.onMutate != hook.onMutate) { - mutationSubscription?.cancel(); - subscribeOnMutate(); - } - if (oldHook.onData != hook.onData || - oldHook.refreshQueries != hook.refreshQueries || - oldHook.refreshInfiniteQueries != hook.refreshInfiniteQueries) { - dataSubscription?.cancel(); - subscribeOnData(); - mutationSubscription?.cancel(); - subscribeOnMutate(); - } - if (oldHook.onError != hook.onError) { - errorSubscription?.cancel(); - subscribeOnError(); - } - } + }; + }, [onData, onError, recoveryData.value, mutation]); - @override - build(BuildContext context) { - if (mutation == null) { - _createMutation(); - } - return mutation!; - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add( - DiagnosticsProperty>( - 'mutation', mutation), - ); - properties.add( - DiagnosticsProperty('mutationKey', hook.mutationKey), - ); - properties.add( - DiagnosticsProperty>( - 'mutationFn', hook.mutationFn), - ); - properties.add( - DiagnosticsProperty('retryConfig', hook.retryConfig), - ); - properties.add( - DiagnosticsProperty>( - 'onData', - hook.onData, - ), - ); - properties.add( - DiagnosticsProperty>( - 'onError', - hook.onError, - ), - ); - properties.add( - DiagnosticsProperty>( - 'onMutation', - hook.onMutate, - ), - ); - } + return mutation; } diff --git a/packages/fl_query_hooks/lib/src/use_query.dart b/packages/fl_query_hooks/lib/src/use_query.dart index 372512d..4a50816 100644 --- a/packages/fl_query_hooks/lib/src/use_query.dart +++ b/packages/fl_query_hooks/lib/src/use_query.dart @@ -1,8 +1,9 @@ import 'dart:async'; import 'package:fl_query/fl_query.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; +import 'package:fl_query_hooks/src/use_query_client.dart'; +import 'package:fl_query_hooks/src/utils/use_updater.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; Query useQuery( @@ -15,185 +16,54 @@ Query useQuery( final ValueChanged? onData, final ValueChanged? onError, - // widget specific + // hook specific final bool enabled = true, }) { - return use( - UseQuery( + final rebuild = useUpdater(); + final client = useQueryClient(); + final query = useMemoized(() { + return client.createQuery( queryKey, queryFn, initial: initial, - retryConfig: retryConfig, - refreshConfig: refreshConfig, jsonConfig: jsonConfig, - onData: onData, - onError: onError, - enabled: enabled, - ), - ); -} - -class UseQuery extends Hook> { - final QueryFn queryFn; - final String queryKey; - - final DataType? initial; - - final RetryConfig retryConfig; - final RefreshConfig refreshConfig; - final JsonConfig? jsonConfig; - - final ValueChanged? onData; - final ValueChanged? onError; - - // hook specific - final bool enabled; - - const UseQuery( - this.queryKey, - this.queryFn, { - this.initial, - this.retryConfig = DefaultConstants.retryConfig, - this.refreshConfig = DefaultConstants.refreshConfig, - this.jsonConfig, - this.onData, - this.onError, - this.enabled = true, - super.keys, - }) : assert( - (jsonConfig != null && enabled) || jsonConfig == null, - 'jsonConfig is only supported when enabled is true', - ); - - @override - HookState, UseQuery> - createState() => _UseQueryState(); -} - -class _UseQueryState extends HookState< - Query, UseQuery> { - Query? query; - - VoidCallback? removeListener; - - StreamSubscription? dataSubscription; - StreamSubscription? errorSubscription; - - void rebuild([_]) { - setState(() {}); - } - - void _createQuery() { - query = QueryClient.of(context).createQuery( - hook.queryKey, - hook.queryFn, - initial: hook.initial, - retryConfig: hook.retryConfig, - refreshConfig: hook.refreshConfig, - jsonConfig: hook.jsonConfig, + refreshConfig: refreshConfig, + retryConfig: retryConfig, ); - } + }, [client, queryKey]); - Future initialize() async { - setState(() { - _createQuery(); - if (hook.onData != null) - dataSubscription = query!.dataStream.listen(hook.onData); - if (hook.onData != null) - errorSubscription = query!.errorStream.listen(hook.onError); + useEffect(() { + return query.addListener(rebuild); + }, [query]); - removeListener = query!.addListener(rebuild); - }); - if (hook.enabled) { - await query!.fetch(); + useEffect(() { + query.updateQueryFn(queryFn); + return null; + }, [queryFn, query]); + + useEffect(() { + if (enabled) { + query.fetch(); } - } + return null; + }, [enabled]); - @override - void initHook() { - super.initHook(); - WidgetsBinding.instance.addPostFrameCallback((_) async { - await initialize(); - }); - } + useEffect(() { + StreamSubscription? dataSubscription; + StreamSubscription? errorSubscription; - @override - void dispose() { - dataSubscription?.cancel(); - errorSubscription?.cancel(); - removeListener?.call(); - super.dispose(); - } + if (onData != null) { + dataSubscription = query.dataStream.listen(onData); + } + if (onError != null) { + errorSubscription = query.errorStream.listen(onError); + } - @override - void didUpdateHook( - UseQuery oldHook, - ) { - super.didUpdateHook(oldHook); - - if (oldHook.queryKey != hook.queryKey) { + return () { dataSubscription?.cancel(); errorSubscription?.cancel(); - removeListener?.call(); - initialize(); - return; - } else if (oldHook.enabled != hook.enabled && hook.enabled) { - query!.fetch(); - } - if (oldHook.queryFn != hook.queryFn) { - query!.updateQueryFn(hook.queryFn); - } - if (oldHook.onData != hook.onData) { - dataSubscription?.cancel(); - if (hook.onData != null) - dataSubscription = query!.dataStream.listen(hook.onData); - } - if (oldHook.onError != hook.onError) { - errorSubscription?.cancel(); - if (hook.onError != null) - errorSubscription = query!.errorStream.listen(hook.onError); - } - } + }; + }, [onData, onError, query]); - @override - Query build(BuildContext context) { - if (query == null) { - _createQuery(); - } - return query!; - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add( - DiagnosticsProperty>('query', query), - ); - properties.add( - DiagnosticsProperty('queryKey', hook.queryKey), - ); - properties.add(DiagnosticsProperty('initial', hook.initial)); - properties.add( - DiagnosticsProperty('retryConfig', hook.retryConfig), - ); - properties.add( - DiagnosticsProperty( - 'refreshConfig', - hook.refreshConfig, - ), - ); - properties.add( - DiagnosticsProperty>( - 'jsonConfig', - hook.jsonConfig, - ), - ); - properties.add( - DiagnosticsProperty>('onData', hook.onData), - ); - properties.add( - DiagnosticsProperty>('onError', hook.onError), - ); - properties.add(DiagnosticsProperty('enabled', hook.enabled)); - } + return query; }