QueryMixin<T extends StatefulWidget> mixin
Reading queries
Mutations
Infinite queries
Adds watchQuery, watchSelectQuery, watchInfiniteQuery and
watchMutation to a State, to read queries flat in its build.
One of the four equal ways to read a query; the others are
QueryContext, the builder widgets such as QueryBuilder, and the
controllers such as QueryController. This one reads like a hook, and
everything it creates belongs to the State: disposed with it, and
recreated when the client above it changes.
class TaskScreen extends StatefulWidget {
const TaskScreen(this.id, {super.key});
final String id;
@override
State<TaskScreen> createState() => _TaskScreenState();
}
class _TaskScreenState extends State<TaskScreen> with QueryMixin {
@override
Widget build(BuildContext context) {
final task = watchQuery(taskQuery(widget.id));
final rename = watchMutation(renameTask(widget.id));
return Column(
children: [
Text(task.dataOrNull?.name ?? '…'),
FilledButton(
onPressed: rename.value.isPending
? null
: () => rename.mutate('Renamed'),
child: const Text('Rename'),
),
],
);
}
}
Identity
Reads are identified by their QueryKey and types, not by call order, so
there is nothing like the rules of hooks: calling watchQuery inside an
if is fine. What that identity does not tell apart — two reads of one
key with different selectors of the same output type, or two mutations of
the same shape, the same mutationKey included — takes an id:, and
reading two that differ without one is caught in debug builds (see
watchMutation for what a mutation is compared by). An id then takes
the key's place in the read's identity, the types staying part of it:
the read keeps its observer when its key changes, which is what
PlaceholderData.compute((previous, _) => previous) needs to keep
showing the previous key's data while the next loads.
When a read is released
A key read in the previous build but not in this one is released after
the frame, and so is a mutation. Everything goes when the State is
disposed. A State that stops calling watchQuery altogether gives no
signal, so its last observers stay until it is disposed; keep a
conditional read in a widget of its own, and the condition becomes that
widget's presence in the tree.
"Build" means this State's own build. A watchQuery inside a nested
builder callback — a ValueListenableBuilder, LayoutBuilder or
AnimatedBuilder in build, or a ListView.builder's itemBuilder —
also reads for this State, but that callback re-runs on its own, so its
reads are additive: they release nothing build read, and a key the
callback stops reading (the layout that was left, the rows scrolled away)
stays subscribed until an own build of this State that reads, or its
disposal. A build that reads nothing itself, leaving every read to a
nested builder, never starts over: those keys stay until the parent
rebuilds this State's widget or it is disposed. Nothing shown in this
State's subtree ever loses its subscription this way. Where the cost
matters — a long list above all, or a key that depends on constraints —
give the nested part, or each row, a widget of its own.
A read belongs to this State and rebuilds it, whoever made it: a dialog
or sheet builder calling watchQuery is not rebuilt by a change, and its
keys go at this State's next build that reads. Give a dialog a reader
of its own.
The client
Reads run on the nearest QueryClientProvider's client. Override
queryClient to read from a client of your own instead — a
widget.client, say; a change of client releases everything held and
recreates it on the new one.
- Superclass constraints
- State<
T>
- State<
Properties
- context → BuildContext
-
The location in the tree where this widget builds.
no setterinherited
- hashCode → int
-
The hash code for this object.
no setterinherited
- mounted → bool
-
Whether this State object is currently in a tree.
no setterinherited
- queryClient → QueryClient
-
The client every read of this
Stateruns on: the nearest QueryClientProvider's by default.no setter - runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- widget → T
-
The current configuration.
no setterinherited
Methods
-
activate(
) → void -
Called when this object is reinserted into the tree after having been
removed via deactivate.
inherited
-
build(
BuildContext context) → Widget -
Describes the part of the user interface represented by this widget.
inherited
-
deactivate(
) → void -
Called when this object is removed from the tree.
inherited
-
debugFillProperties(
DiagnosticPropertiesBuilder properties) → void -
Add additional properties associated with the node.
inherited
-
didChangeDependencies(
) → void -
Called when a dependency of this State object changes.
inherited
-
didUpdateWidget(
covariant T oldWidget) → void -
Called whenever the widget configuration changes.
inherited
-
dispose(
) → void -
Called when this object is removed from the tree permanently.
override
-
initState(
) → void -
Called when this object is inserted into the tree.
inherited
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
reassemble(
) → void -
Called whenever the application is reassembled during debugging, for
example during hot reload.
inherited
-
setState(
VoidCallback fn) → void -
Notify the framework that the internal state of this object has changed.
inherited
-
toDiagnosticsNode(
{String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode -
Returns a debug representation of the object that is used by debugging
tools and by DiagnosticsNode.toStringDeep.
inherited
-
toString(
{DiagnosticLevel minLevel = DiagnosticLevel.info}) → String -
A string representation of this object.
inherited
-
toStringShort(
) → String -
A brief description of this object, usually just the runtimeType and the
hashCode.
inherited
-
watchInfiniteQuery<
TPageData, TPageParam, TData> (InfiniteQueryObserverOptionsBase< TPageData, TPageParam, TData> options, {Object? id, BuildWhen<QueryResult< ? buildWhen}) → InfiniteQueryController<TData> >TPageData, TPageParam, TData> - watchQuery for an infinite query. Returns the controller rather than the result, because paging lives on it.
-
watchMutation<
TData, TVariables, TOnMutateResult> (MutationOptions< TData, TVariables, TOnMutateResult> options, {Object? id, BuildWhen<MutationResult< ? buildWhen}) → MutationController<TData, TVariables> >TData, TVariables, TOnMutateResult> -
A mutation owned by this
State, as a MutationController. -
watchQuery<
TData> (QueryObserverOptions< TData> options, {Object? id, BuildWhen<QueryResult< ? buildWhen}) → QueryResult<TData> >TData> -
Subscribes this
Statetooptions's query and returns its current result. -
watchSelectQuery<
TQueryData, TData> (QuerySelectOptions< TQueryData, TData> options, {Object? id, BuildWhen<QueryResult< ? buildWhen}) → QueryResult<TData> >TData> -
watchQuery for a query with a
select: the cache holdsTQueryData, thisStateseesTData.
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited