useQuery<TData, TError> function

UseQueryResult<TData, TError> useQuery<TData, TError>(
  1. RawQueryKey queryKey,
  2. QueryFn<TData> fetcher, {
  3. bool enabled = true,
  4. RefetchOnMount? refetchOnMount,
  5. Duration? staleDuration,
  6. Duration? cacheDuration,
  7. Duration? refetchInterval,
  8. int? retryCount,
  9. Duration? retryDelay,
})

Builds and subscribes to a query stored in the cache. Takes a query key and a fetcher function which either resolves or throws an error. Returns a UseQueryResult

Example:

// These are default configurations
final posts = useQuery(
  ['posts'],
  getPosts,
  enabled: true,
  cacheDuration: const Duration(minutes: 5),
  refetchInterval: null // The query will not refetch by default,
  refetchOnMount: RefetchOnMount.stale,
  staleDuration: const Duration(seconds: 10),
);
  • enabled - specifies if the query fetcher function is automatically called when the widget renders, can be used for dependent queries.
  • cacheDuration - specifies the duration unused/inactive cache data remains in memory; the cached data will be garbage collected after this duration. The longest duration will be used when different values are specified in multiple instances of the query.
  • refetchInterval - specifies the time interval in which all queries will refetch the data, setting it to null (default) will turn off refetching
  • refetchOnMount - specifies the behavior of the query instance when the widget is first built and the data is already available.
    • RefetchOnMount.always - will always refetch when the widget is built.
    • RefetchOnMount.stale - will fetch the data if it is stale (see staleDuration).
    • RefetchOnMount.never - will never refetch.
  • staleDuration - specifies the duration until the data becomes stale. This value applies to each query instance individually.

Implementation

UseQueryResult<TData, TError> useQuery<TData, TError>(
  RawQueryKey queryKey,
  QueryFn<TData> fetcher, {
  // These options must match with the `UseQueryOptions`
  bool enabled = true,
  RefetchOnMount? refetchOnMount,
  Duration? staleDuration,
  Duration? cacheDuration,
  Duration? refetchInterval,
  int? retryCount,
  Duration? retryDelay,
}) {
  final options = useMemoized(
    () => UseQueryOptions<TData, TError>(
      enabled: enabled,
      refetchOnMount: refetchOnMount,
      staleDuration: staleDuration,
      cacheDuration: cacheDuration,
      refetchInterval: refetchInterval,
      retryCount: retryCount,
      retryDelay: retryDelay,
    ),
    [
      enabled,
      refetchOnMount,
      staleDuration,
      cacheDuration,
      refetchInterval,
      retryCount,
      retryDelay
    ],
  );
  final client = useQueryClient();

  final observerRef = useRef<Observer<TData, TError>?>(null);
  useEffect(() {
    observerRef.value = Observer(
      QueryKey(queryKey),
      fetcher,
      client: client,
      options: options,
    );
    return;
  }, [QueryKey(queryKey)]);

  // Rebuild observer if the query is changed somehow,
  // typically when the query is removed from the cache.
  final query = useListenableSelector(
    client.queryCache,
    () => client.queryCache.queries[QueryKey(queryKey)],
  );
  useEffect(() {
    if (query == null) {
      observerRef.value = Observer(
        QueryKey(queryKey),
        fetcher,
        client: client,
        options: options,
      );
    }
    return;
  }, [query]);

  final observer = observerRef.value as Observer<TData, TError>;

  // This subscribes to the observer
  // and rebuilds the widgets on updates.
  useListenable<Observer<TData, TError>>(observer);

  useEffect(() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      observer.updateOptions(options);
    });
    return;
  }, [observer, options]);

  useEffect(() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      observer.initialize();
    });
    return () {
      observer.destroy();
    };
  }, [observer]);

  return UseQueryResult<TData, TError>(
    data: observer.query.state.data,
    dataUpdatedAt: observer.query.state.dataUpdatedAt,
    error: observer.query.state.error,
    errorUpdatedAt: observer.query.state.errorUpdatedAt,
    isError: observer.query.state.isError,
    isLoading: observer.query.state.isLoading,
    isFetching: observer.query.state.isFetching,
    isSuccess: observer.query.state.isSuccess,
    status: observer.query.state.status,
    refetch: observer.fetch,
    isInvalidated: observer.query.state.isInvalidated,
    isRefetchError: observer.query.state.isRefetchError,
  );
}