Flutter Query

Flutter Query

Quick Start

Build a Flutter app that fetches data in just a few minutes

In this guide, you will build a Flutter app that fetches data from a server and displays it on the screen. By the end, you will have a working example that shows loading, success, and error states automatically.

Prerequisites

Before starting, make sure you have:

  • Flutter installed and working
  • A Flutter project set up

Install the package

Add flutter_query and flutter_hooks to your project:

Terminal
flutter pub add flutter_query flutter_hooks

You will notice two packages added to your pubspec.yaml:

pubspec.yaml
dependencies:
  flutter_query: ^0.3.7
  flutter_hooks: ^0.21.2

Set up the QueryClientProvider

Open your main.dart file and wrap your app with QueryClientProvider:

main.dart
import 'package:flutter/material.dart';
import 'package:flutter_query/flutter_query.dart';

void main() {
  runApp(
    QueryClientProvider(
      client: QueryClient(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

This makes the query client available to all widgets in your app.

Create a data fetching function

Create a function that fetches data. For this example, create a simple function that simulates a network request:

main.dart
Future<String> fetchGreeting() async {
  // Simulate a network delay
  await Future.delayed(const Duration(seconds: 2));
  return 'Hello Flutter Query!';
}

This function is completely independent of Flutter Query. It just fetches data and returns a Future. Keeping your data fetching logic separate makes it easier to test and reuse across your app.

Use the query hook

Create a widget that uses useQuery to fetch and display the data. The widget must extend HookWidget:

main.dart
import 'package:flutter_hooks/flutter_hooks.dart';

class HomePage extends HookWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    final result = useQuery(
      const ['greeting'],
      (context) => fetchGreeting(),
    );

    return Scaffold(
      appBar: AppBar(title: const Text('Quick Start')),
      body: Center(
        child: Builder(
          builder: (context) {
            if (result.isLoading) {
              return const CircularProgressIndicator();
            }

            if (result.isError) {
              return Text('Error: ${result.error}');
            }

            return Text(result.data!);
          },
        ),
      ),
    );
  }
}

useQuery takes two required arguments:

  • A query key — a list of identifiers that uniquely identifies this query
  • A query function — an asynchronous function that fetches your data

Run the app

Run your app:

Terminal
flutter run

You will see a loading spinner for 2 seconds, then the greeting message appears.

The command will prompt you to select a platform. Choose any platform you have set up. If you have Chrome installed, selecting web is a fast way to see your app running quickly.

Complete code

Here is the full main.dart file:

main.dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_query/flutter_query.dart';

void main() {
  runApp(
    QueryClientProvider(
      client: QueryClient(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

Future<String> fetchGreeting() async {
  await Future.delayed(const Duration(seconds: 2));
  return 'Hello Flutter Query!';
}

class HomePage extends HookWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    final result = useQuery(
      const ['greeting'],
      (context) => fetchGreeting(),
    );

    return Scaffold(
      appBar: AppBar(title: const Text('Quick Start')),
      body: Center(
        child: Builder(
          builder: (context) {
            if (result.isLoading) {
              return const CircularProgressIndicator();
            }

            if (result.isError) {
              return Text('Error: ${result.error}');
            }

            return Text(result.data!);
          },
        ),
      ),
    );
  }
}

Next steps

You now have a working Flutter Query setup. The query result automatically handles loading and error states, and will cache the data for future use.

To continue exploring, try:

  • Changing the query function to return different data types
  • Adding a button that calls result.refetch() to refresh the data
  • Using multiple useQuery calls in the same widget

On this page