Handle loading/errors

As we saw in the previous step, we got various variables in QueryResult object. Among them loading and errors are common ones that you will need to handle in your app.

Now let's go back to the Query widget that you wrote in the previous step.

options: QueryOptions(
document: TodoFetch.fetchAll,
variables: {"is_public": false},
builder: (QueryResult result, {VoidCallback refetch}) {
refetchQuery = refetch;
if (result.errors != null) {
return Text(result.errors.toString());
if (result.loading) {
return Text('Loading');
final List<LazyCacheMap> todos =
(result.data['todos'] as List<dynamic>).cast<LazyCacheMap>();
return ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
dynamic responseData = todos[index];
return TodoItemTile(
item: TodoItem.fromElements(responseData["id"],
responseData['title'], responseData['is_completed']),
toggleDocument: TodoFetch.toggleTodo,
toggleRunMutaion: {
'id': responseData["id"],
'isCompleted': !responseData['is_completed']
deleteDocument: TodoFetch.deleteTodo,
deleteRunMutaion: {
'id': responseData["id"],
refetchQuery: refetch,

When Query's builder runs you can manage states of your app like loading and error.
In loading state, typically you can do fancy things like displaying a loading spinner.

We are just printing error but you can handle it also, by navigating to some screen or showing some pop up.

All said and done, What you have written above is basic, but sufficient for this tutorial.

Did you find this page helpful?
Start with GraphQL on Hasura for Free
  • ArrowBuild apps and APIs 10x faster
  • ArrowBuilt-in authorization and caching
  • Arrow8x more performant than hand-rolled APIs
footer illustration
Brand logo
© 2024 Hasura Inc. All rights reserved