feat: pass variableKey to task fn in withVariableKey method
This commit is contained in:
@@ -0,0 +1,186 @@
|
|||||||
|
---
|
||||||
|
title: Jobs API
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
import Tabs from "@theme/Tabs";
|
||||||
|
import TabItem from "@theme/TabItem";
|
||||||
|
|
||||||
|
All this time, we've been directly supplying `queryKey`, `queryFn` etc to `QueryBuilder` and so on. But this might looks repetetive or might break the rules of DRY (Don't Repeat Yourself). So to tackle this issue Fl-Query has an alternate API to create queries/infinite queries/mutations.
|
||||||
|
|
||||||
|
Jobs are nothing but a collection of arguments of `*Builder`s. It is just a more declarative way to create queries/infinite queries/mutations.
|
||||||
|
|
||||||
|
## Query Job
|
||||||
|
|
||||||
|
A `QueryJob` consists of same arguments as `QueryBuilder`
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final job = QueryJob<List<Todo>, dynamic, HttpApi>(
|
||||||
|
queryKey: "todos",
|
||||||
|
task: (api) => api.getTodos(),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
You might notice the third type argument `HttpApi`. That's the new `ArgsType`. Because QueryJob is isolated from widget tree and outside APIs are not accessible from there, you've to manually pass anything you need to the `task` function. In this case, we need an instance of `HttpApi` to call `getTodos()`.
|
||||||
|
|
||||||
|
### `QueryBuilder.withJob` and `useQueryJob`
|
||||||
|
|
||||||
|
`QueryBuilder.withJob` is a static method that takes a `QueryJob` and returns a `QueryBuilder`. It also accepts event callbacks such as `onError` and `onData`. Also a special argument called `args` which is passed to the `task` function.
|
||||||
|
|
||||||
|
Similarly, we have a `useQueryJob` if you're using `flutter_hooks`
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<TabItem value="vanilla" label="Vanilla">
|
||||||
|
|
||||||
|
```dart
|
||||||
|
QueryBuilder.withJob(
|
||||||
|
job: job, // QueryJob we created earlier
|
||||||
|
args: httpApi,
|
||||||
|
onError: (error) => print(error),
|
||||||
|
onData: (data) => print(data),
|
||||||
|
builder: /* ... */,
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="flutter_hooks" label="Flutter Hooks">
|
||||||
|
|
||||||
|
```dart
|
||||||
|
useQueryJob(
|
||||||
|
job: job, // QueryJob we created earlier
|
||||||
|
args: httpApi,
|
||||||
|
onError: (error) => print(error),
|
||||||
|
onData: (data) => print(data),
|
||||||
|
builder: /* ... */,
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
## InfiniteQuery Job
|
||||||
|
|
||||||
|
Just like `QueryJob`, `InfiniteQueryJob` is the collection of arguments that is passed to `InfiniteQueryBuilder` or `useInfiniteQuery`
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final job = InfiniteQueryBuilder<PagedProducts, ClientException, int, HttpApi>(
|
||||||
|
queryKey: "products",
|
||||||
|
task: (page, api) => api.getProductsPaginated(page),
|
||||||
|
nextPage: (lastPage, lastPageData) {
|
||||||
|
/// returning [null] will set [hasNextPage] to [false]
|
||||||
|
if (lastPageData.products.length < 10) return null;
|
||||||
|
return lastPage + 1;
|
||||||
|
},
|
||||||
|
initialPage: 0,
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### `InfiniteQueryBuilder.withJob` and `useInfiniteQueryJob`
|
||||||
|
|
||||||
|
Just like `QueryBuilder.withJob`, `InfiniteQueryBuilder.withJob` is a static method that takes a `InfiniteQueryJob` and returns a `InfiniteQueryBuilder`. It also accepts event callbacks such as `onError` and `onData`. Also a special argument called `args` which is passed to the `task` function.
|
||||||
|
|
||||||
|
Simiarly, we have a `useInfiniteQueryJob` if you're using `flutter_hooks`
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<TabItem value="vanilla" label="Vanilla">
|
||||||
|
|
||||||
|
```dart
|
||||||
|
InfiniteQueryBuilder.withJob(
|
||||||
|
job: job, // InfiniteQueryJob we created earlier
|
||||||
|
args: httpApi,
|
||||||
|
onError: (error) => print(error),
|
||||||
|
onData: (data) => print(data),
|
||||||
|
builder: /* ... */,
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="flutter_hooks" label="Flutter Hooks">
|
||||||
|
|
||||||
|
```dart
|
||||||
|
useInfiniteQueryJob(
|
||||||
|
job: job, // InfiniteQueryJob we created earlier
|
||||||
|
args: httpApi,
|
||||||
|
onError: (error) => print(error),
|
||||||
|
onData: (data) => print(data),
|
||||||
|
builder: /* ... */,
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
|
||||||
|
## Mutation Job
|
||||||
|
|
||||||
|
For mutations we've `MutationJob` it is similar to `QueryJob` but has `mutationKey` instead of `queryKey`
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final job = MutationJob<Todo, dynamic, Todo, void, HttpApi>(
|
||||||
|
mutationKey: "create-todo",
|
||||||
|
task: (variables, api) => api.createTodo(),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
:::info
|
||||||
|
`MutationJob` has both `variables` and `args` which can be confusing. But use variables for passing data that are supposed to be sent, that means data that can change on next mutation.
|
||||||
|
|
||||||
|
Use `args` for passing anything that is not supposed to change, like an API instance, authentication info or a config etc.
|
||||||
|
:::
|
||||||
|
|
||||||
|
### `MutationBuilder.withJob` and `useMutationJob`
|
||||||
|
|
||||||
|
Just like `QueryBuilder.withJob`, `MutationBuilder.withJob` is a static method that takes a `MutationJob` and returns a `MutationBuilder`. It also accepts event callbacks such as `onMutate`, `onError` and `onData`. Also a special argument called `args` which is passed to the `task` function.
|
||||||
|
|
||||||
|
Simiarly, we have a `useMutationJob` if you're using `flutter_hooks`
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<TabItem value="vanilla" label="Vanilla">
|
||||||
|
|
||||||
|
```dart
|
||||||
|
MutationBuilder.withJob(
|
||||||
|
job: job, // MutationJob we created earlier
|
||||||
|
args: httpApi,
|
||||||
|
onError: (error) => print(error),
|
||||||
|
onData: (data) => print(data),
|
||||||
|
builder: /* ... */,
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="flutter_hooks" label="Flutter Hooks">
|
||||||
|
|
||||||
|
```dart
|
||||||
|
useInfiniteQueryJob(
|
||||||
|
job: job, // MutationJob we created earlier
|
||||||
|
args: httpApi,
|
||||||
|
onError: (error) => print(error),
|
||||||
|
onData: (data) => print(data),
|
||||||
|
builder: /* ... */,
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
## Dynamic Jobs
|
||||||
|
|
||||||
|
Every job has `.withVariableKey` static that allows creating queries/mutations with changing data on the fly. It returns a function that accepts a variable key (String). Which will create a new instance of the job with the new variable key.
|
||||||
|
|
||||||
|
Here's the example usage for `Query`:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final job = QueryJob.withVariableKey<List<Todo>, dynamic, HttpApi>(
|
||||||
|
baseQueryKey: "todos/", // the variable key will be appended to this
|
||||||
|
task: (variableKey, api) => api.getTodo(variableKey),
|
||||||
|
);
|
||||||
|
|
||||||
|
// later in the widget tree
|
||||||
|
QueryBuilder.withJob(
|
||||||
|
job: job(todoId),
|
||||||
|
args: httpApi,
|
||||||
|
builder: /* ... */,
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Everything is just as same as for `Mutation` and `InfiniteQuery`..
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: Optimistic Updates
|
title: Optimistic Updates
|
||||||
sidebar_position: 1
|
sidebar_position: 2
|
||||||
---
|
---
|
||||||
import Tabs from '@theme/Tabs';
|
import Tabs from '@theme/Tabs';
|
||||||
import TabItem from '@theme/TabItem';
|
import TabItem from '@theme/TabItem';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: Persisting Queries
|
title: Persisting Queries
|
||||||
sidebar_position: 1
|
sidebar_position: 3
|
||||||
---
|
---
|
||||||
import Tabs from '@theme/Tabs';
|
import Tabs from '@theme/Tabs';
|
||||||
import TabItem from '@theme/TabItem';
|
import TabItem from '@theme/TabItem';
|
||||||
|
|||||||
@@ -8,9 +8,6 @@ Fl-Query V1 comes with lot of breaking changes in the API. It is not possible to
|
|||||||
|
|
||||||
## Removal of APIs/methods/properties
|
## Removal of APIs/methods/properties
|
||||||
|
|
||||||
- `QueryJob`, `MutationJob` and `InfiniteQueryJob` all were removed to bring the API closer to React Query. The `externalData` param was found to be vulnerable and was causing memory leaks. Also the query itself should not react to external data changes automatically which caused massive performance drawbacks and circular dependency related issues.
|
|
||||||
|
|
||||||
Now everything needs to be passed to `QueryBuilder`, `MutationBuilder` and `InfiniteQueryBuilder` or `useQuery`, `useMutation` and `useInfiniteQuery` hooks directly.
|
|
||||||
- `keepPreviousData` has been removed from both `Query` and `InfiniteQuery`
|
- `keepPreviousData` has been removed from both `Query` and `InfiniteQuery`
|
||||||
- `QueryClient`'s (formerly `QueryBowl`)
|
- `QueryClient`'s (formerly `QueryBowl`)
|
||||||
- `prefetchQuery` method was removed
|
- `prefetchQuery` method was removed
|
||||||
@@ -51,6 +48,7 @@ Fl-Query V1 comes with lot of breaking changes in the API. It is not possible to
|
|||||||
- `QueryBowlProvider` was renamed to `QueryClientProvider`
|
- `QueryBowlProvider` was renamed to `QueryClientProvider`
|
||||||
- `Query.refetch` was renamed to `Query.refresh`
|
- `Query.refetch` was renamed to `Query.refresh`
|
||||||
- `InfiniteQuery.refetchPages` has been replaced with `InfiniteQuery.refresh` and `InfiniteQuery.refreshAll`
|
- `InfiniteQuery.refetchPages` has been replaced with `InfiniteQuery.refresh` and `InfiniteQuery.refreshAll`
|
||||||
|
- `externalData` was renamed to `args` for `QueryJob`, `InfiniteQueryJob` and `MutationJob`
|
||||||
|
|
||||||
Now instead of passing callback, `Future.wait` is used with `refresh` to refetch a segment of pages.
|
Now instead of passing callback, `Future.wait` is used with `refresh` to refetch a segment of pages.
|
||||||
`refreshAll` is a shorthand to refetch all pages at once.
|
`refreshAll` is a shorthand to refetch all pages at once.
|
||||||
@@ -62,6 +60,8 @@ Fl-Query V1 comes with lot of breaking changes in the API. It is not possible to
|
|||||||
|
|
||||||
All the retry & cache invalidation related properties were moved to their own classes.
|
All the retry & cache invalidation related properties were moved to their own classes.
|
||||||
|
|
||||||
|
- `QueryBuilder`, `InfiniteQueryBuilder` and `MutationBuilder` doesn't accept jobs by default. To use the old Jobs API, `.withJob` constructor must be used.
|
||||||
|
- Similarly, `useQuery`, `useInfiniteQuery`, `useMutation` doesn't accept jobs now. Use `useQueryJob`, `useInfiniteQueryJob` and `useMutationJob` instead.
|
||||||
- Retry related properties were moved to `RetryConfig` class
|
- Retry related properties were moved to `RetryConfig` class
|
||||||
- `retries` was renamed to `maxRetries`
|
- `retries` was renamed to `maxRetries`
|
||||||
- Cache invalidation related properties were moved to `RefreshConfig` class
|
- Cache invalidation related properties were moved to `RefreshConfig` class
|
||||||
|
|||||||
@@ -6,6 +6,13 @@ import 'package:fl_query/src/core/infinite_query.dart';
|
|||||||
typedef InfiniteQueryJobFn<DataType, PageType, ArgsType> = Future<DataType>
|
typedef InfiniteQueryJobFn<DataType, PageType, ArgsType> = Future<DataType>
|
||||||
Function(PageType page, ArgsType args);
|
Function(PageType page, ArgsType args);
|
||||||
|
|
||||||
|
typedef InfiniteQueryJobVariableFn<DataType, PageType, ArgsType>
|
||||||
|
= Future<DataType> Function(
|
||||||
|
String variableKey,
|
||||||
|
PageType page,
|
||||||
|
ArgsType args,
|
||||||
|
);
|
||||||
|
|
||||||
typedef InfiniteQueryJobVariableKeyFn<DataType, ErrorType, PageType, ArgsType>
|
typedef InfiniteQueryJobVariableKeyFn<DataType, ErrorType, PageType, ArgsType>
|
||||||
= InfiniteQueryJob<DataType, ErrorType, PageType, ArgsType> Function(
|
= InfiniteQueryJob<DataType, ErrorType, PageType, ArgsType> Function(
|
||||||
String variable);
|
String variable);
|
||||||
@@ -40,7 +47,7 @@ class InfiniteQueryJob<DataType, ErrorType, PageType, ArgsType> {
|
|||||||
static InfiniteQueryJobVariableKeyFn<DataType, ErrorType, PageType, ArgsType>
|
static InfiniteQueryJobVariableKeyFn<DataType, ErrorType, PageType, ArgsType>
|
||||||
withVariableKey<DataType, ErrorType, PageType, ArgsType>({
|
withVariableKey<DataType, ErrorType, PageType, ArgsType>({
|
||||||
required String baseQueryKey,
|
required String baseQueryKey,
|
||||||
required InfiniteQueryJobFn<DataType, PageType, ArgsType?> task,
|
required InfiniteQueryJobVariableFn<DataType, PageType, ArgsType?> task,
|
||||||
required final InfiniteQueryNextPage<DataType, PageType> nextPage,
|
required final InfiniteQueryNextPage<DataType, PageType> nextPage,
|
||||||
required final PageType initialPage,
|
required final PageType initialPage,
|
||||||
RetryConfig? retryConfig,
|
RetryConfig? retryConfig,
|
||||||
@@ -48,9 +55,9 @@ class InfiniteQueryJob<DataType, ErrorType, PageType, ArgsType> {
|
|||||||
JsonConfig<DataType>? jsonConfig,
|
JsonConfig<DataType>? jsonConfig,
|
||||||
bool enabled = true,
|
bool enabled = true,
|
||||||
}) {
|
}) {
|
||||||
return (String variable) => InfiniteQueryJob(
|
return (String variableKey) => InfiniteQueryJob(
|
||||||
queryKey: "$baseQueryKey$variable",
|
queryKey: "$baseQueryKey$variableKey",
|
||||||
task: task,
|
task: (page, args) => task(variableKey, page, args),
|
||||||
nextPage: nextPage,
|
nextPage: nextPage,
|
||||||
initialPage: initialPage,
|
initialPage: initialPage,
|
||||||
retryConfig: retryConfig,
|
retryConfig: retryConfig,
|
||||||
|
|||||||
@@ -6,6 +6,13 @@ typedef MutationJobFn<DataType, VariablesType, ArgsType> = Future<DataType>
|
|||||||
ArgsType args,
|
ArgsType args,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
typedef MutationJobVariableFn<DataType, VariablesType, ArgsType>
|
||||||
|
= Future<DataType> Function(
|
||||||
|
String variableKey,
|
||||||
|
VariablesType variables,
|
||||||
|
ArgsType args,
|
||||||
|
);
|
||||||
|
|
||||||
typedef MutationJobVariableKeyFn<DataType, ErrorType, VariablesType,
|
typedef MutationJobVariableKeyFn<DataType, ErrorType, VariablesType,
|
||||||
RecoveryType, ArgsType>
|
RecoveryType, ArgsType>
|
||||||
= MutationJob<DataType, ErrorType, VariablesType, RecoveryType, ArgsType>
|
= MutationJob<DataType, ErrorType, VariablesType, RecoveryType, ArgsType>
|
||||||
@@ -33,14 +40,14 @@ class MutationJob<DataType, ErrorType, VariablesType, RecoveryType, ArgsType> {
|
|||||||
withVariableKey<DataType, ErrorType, VariablesType, RecoveryType,
|
withVariableKey<DataType, ErrorType, VariablesType, RecoveryType,
|
||||||
ArgsType>({
|
ArgsType>({
|
||||||
required String baseMutationKey,
|
required String baseMutationKey,
|
||||||
required MutationJobFn<DataType, VariablesType, ArgsType?> task,
|
required MutationJobVariableFn<DataType, VariablesType, ArgsType?> task,
|
||||||
RetryConfig? retryConfig,
|
RetryConfig? retryConfig,
|
||||||
List<String>? refreshQueries,
|
List<String>? refreshQueries,
|
||||||
List<String>? refreshInfiniteQueries,
|
List<String>? refreshInfiniteQueries,
|
||||||
}) {
|
}) {
|
||||||
return (String variable) => MutationJob(
|
return (String variableKey) => MutationJob(
|
||||||
mutationKey: "$baseMutationKey$variable",
|
mutationKey: "$baseMutationKey$variableKey",
|
||||||
task: task,
|
task: (variables, args) => task(variableKey, variables, args),
|
||||||
retryConfig: retryConfig,
|
retryConfig: retryConfig,
|
||||||
refreshQueries: refreshQueries,
|
refreshQueries: refreshQueries,
|
||||||
refreshInfiniteQueries: refreshInfiniteQueries,
|
refreshInfiniteQueries: refreshInfiniteQueries,
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import 'package:fl_query/src/collections/retry_config.dart';
|
|||||||
|
|
||||||
typedef QueryJobFn<DataType, ArgsType> = Future<DataType> Function(
|
typedef QueryJobFn<DataType, ArgsType> = Future<DataType> Function(
|
||||||
ArgsType args);
|
ArgsType args);
|
||||||
|
typedef QueryJobVariableFn<DataType, ArgsType> = Future<DataType> Function(
|
||||||
|
String variableKey,
|
||||||
|
ArgsType args,
|
||||||
|
);
|
||||||
|
|
||||||
typedef QueryJobVariableKeyFn<DataType, ErrorType, ArgsType>
|
typedef QueryJobVariableKeyFn<DataType, ErrorType, ArgsType>
|
||||||
= QueryJob<DataType, ErrorType, ArgsType> Function(String variable);
|
= QueryJob<DataType, ErrorType, ArgsType> Function(String variable);
|
||||||
@@ -37,16 +41,16 @@ class QueryJob<DataType, ErrorType, ArgsType> {
|
|||||||
static QueryJobVariableKeyFn<DataType, ErrorType, ArgsType>
|
static QueryJobVariableKeyFn<DataType, ErrorType, ArgsType>
|
||||||
withVariableKey<DataType, ErrorType, ArgsType>({
|
withVariableKey<DataType, ErrorType, ArgsType>({
|
||||||
required String baseQueryKey,
|
required String baseQueryKey,
|
||||||
required QueryJobFn<DataType, ArgsType?> task,
|
required QueryJobVariableFn<DataType, ArgsType?> task,
|
||||||
DataType? initial,
|
DataType? initial,
|
||||||
RetryConfig? retryConfig,
|
RetryConfig? retryConfig,
|
||||||
RefreshConfig? refreshConfig,
|
RefreshConfig? refreshConfig,
|
||||||
JsonConfig<DataType>? jsonConfig,
|
JsonConfig<DataType>? jsonConfig,
|
||||||
bool enabled = true,
|
bool enabled = true,
|
||||||
}) {
|
}) {
|
||||||
return (String variable) => QueryJob(
|
return (String variableKey) => QueryJob(
|
||||||
queryKey: "$baseQueryKey$variable",
|
queryKey: "$baseQueryKey$variableKey",
|
||||||
task: task,
|
task: (args) => task(variableKey, args),
|
||||||
initial: initial,
|
initial: initial,
|
||||||
retryConfig: retryConfig,
|
retryConfig: retryConfig,
|
||||||
refreshConfig: refreshConfig,
|
refreshConfig: refreshConfig,
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
Query<DataType, ErrorType> useQueryJob<DataType, ErrorType, ArgsType>({
|
Query<DataType, ErrorType> useQueryJob<DataType, ErrorType, ArgsType>({
|
||||||
required QueryJob<DataType, ErrorType, ArgsType> job,
|
required QueryJob<DataType, ErrorType, ArgsType> job,
|
||||||
|
required ArgsType args,
|
||||||
ValueChanged<DataType>? onData,
|
ValueChanged<DataType>? onData,
|
||||||
ValueChanged<ErrorType>? onError,
|
ValueChanged<ErrorType>? onError,
|
||||||
required ArgsType args,
|
|
||||||
}) {
|
}) {
|
||||||
return useQuery<DataType, ErrorType>(
|
return useQuery<DataType, ErrorType>(
|
||||||
job.queryKey,
|
job.queryKey,
|
||||||
|
|||||||
Reference in New Issue
Block a user