Dependent Queries
Dependent queries are queries that should only execute after some other data is available.
Usage
Use the enabled option in QueryOptions to delay execution until a condition is met.
// 1. Fetch the User first
final userQuery = QueryBuilder<User>(
queryKey: 'user'.toQueryKey(),
/* ... */
);
// 2. Fetch Posts *only* when User ID is available
QueryBuilder<List<Post>>(
// Key depends on user ID
queryKey: 'posts:${userQuery.state.data?.id}'.toQueryKey(),
queryFn: () => api.fetchPosts(userQuery.state.data!.id),
// Disable until we have the ID
options: QueryOptions(
enabled: userQuery.state.hasData, // <--- The magic switch
),
builder: (context, state) {
if (state.isIdle) return Text('Waiting for user...');
/* ... */
}
)API
| Option | Type | Description |
|---|---|---|
enabled | bool | Set to false to prevent the query from fetching automatically. Defaults to true. |
Examples
Serial Fetching
Sometimes you need to chain requests A -> B -> C.
// This pattern typically involves nesting QueryBuilders
// or using the result of one query to drive the next.
QueryBuilder<User>(
queryKey: 'user'.toQueryKey(),
builder: (context, userState) {
if (!userState.hasData) return Loading();
return QueryBuilder<List<Project>>(
// Dependent key
queryKey: 'projects:${userState.data.id}'.toQueryKey(),
queryFn: () => fetchProjects(userState.data.id),
// Only run when user is loaded (redundant if nested, but good practice)
options: QueryOptions(enabled: userState.hasData),
builder: (context, projectState) {
// ...
}
);
}
)Waiting for User Input
Don’t search until the user types something.
QueryBuilder(
queryKey: 'search:$searchTerm'.toQueryKey(),
queryFn: () => searchApi(searchTerm),
options: QueryOptions(
enabled: searchTerm.isNotEmpty, // Only fetch if text exists
),
/* ... */
)Lifecycle Dependencies (Cascading Cancellation)
While enabled controls when a query starts, the dependsOn parameter controls when a query stops.
Use dependsOn to link a child query to a parent query. If the parent query is disposed (removed from memory), the child query is automatically cancelled. This prevents orphan requests from consuming resources when their conceptual “owner” is gone.
// Parent Query (e.g., User Profile)
final userKey = 'user:123'.toQueryKey();
final userQuery = client.getQuery(userKey, /* ... */);
// Child Query (e.g., User Posts)
client.getQuery(
'user:123:posts'.toQueryKey(),
queryFn: () => api.fetchUserPosts(123),
// 🔗 Link to parent
dependsOn: userKey,
);When to use dependsOn?
- Detail Views: A “User Details” query should depend on the “Users List” query if logically nested.
- Drill-downs:
Order Itemsshould depend onOrder. - Resource ownership: If
Query Bmakes no sense withoutQuery Aexisting, link them.
Cancellation Behavior
- Parent Disposed: When the parent query hits 0 subscribers and its garbage collection timer expires.
- Cascade: The
QueryClientdetects the disposal and immediately runs.cancel()on all registered children. - Effect: Any in-flight network requests for the children are aborted. The children are not removed from cache immediately (they follow their own GC logic), but their fetching is stopped.
Last updated on