# Async Data

Sometimes you'll want to load data asynchronously. In that case, you'll want to
pass the params to the screen that's going to show the data and let it do the
lookup itself:

```dart
late final _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomeScreenWithAsync(),
      routes: [
        GoRoute(
          path: 'family/:fid',
          builder: (context, state) => FamilyScreenWithAsync(
            fid: state.params['fid']!,
          ),
          routes: [
            GoRoute(
              path: 'person/:pid',
              builder: (context, state) => PersonScreenWithAsync(
                fid: state.params['fid']!,
                pid: state.params['pid']!,
              ),
            ),
          ],
        ),
      ],
    ),
  ],
);
```

The screen can use whatever it likes to do the lookup. For example, the
following shows the use of [the Repository
pattern](https://martinfowler.com/eaaCatalog/repository.html) and [the Flutter
`FutureBuilder`](https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html)
to load and show the data:

```dart
class FamilyScreen extends StatefulWidget {
  const FamilyScreen({required this.fid, Key? key}) : super(key: key);
  final String fid;

  @override
  State<FamilyScreen> createState() => _FamilyScreenState();
}

class _FamilyScreenState extends State<FamilyScreen> {
  Future<Family>? _future;

  @override
  void initState() {
    super.initState();
    _fetch();
  }

  @override
  void didUpdateWidget(covariant FamilyScreen oldWidget) {
    super.didUpdateWidget(oldWidget);

    // refresh cached data
    if (oldWidget.fid != widget.fid) _fetch();
  }

  void _fetch() => _future = App.repo.getFamily(widget.fid);

  @override
  Widget build(BuildContext context) => FutureBuilder<Family>(
        future: _future,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Scaffold(
              appBar: AppBar(title: const Text('Loading...')),
              body: const Center(child: CircularProgressIndicator()),
            );
          }

          if (snapshot.hasError) {
            return Scaffold(
              appBar: AppBar(title: const Text('Error')),
              body: SnapshotError(snapshot.error!),
            );
          }

          assert(snapshot.hasData);
          final family = snapshot.data!;
          return Scaffold(
            appBar: AppBar(title: Text(family.name)),
            body: ListView(
              children: [
                for (final p in family.people)
                  ListTile(
                    title: Text(p.name),
                    onTap: () => context.go(
                      '/family/${family.id}/person/${p.id}',
                    ),
                  ),
              ],
            ),
          );
        },
      );
}
```

This code shows a progress indicator as the data is being fetched and an error
in the case that the fetch fails. 

![async data example](/images/async.gif)

Take a look at the [async
example](https://github.com/csells/go_router/blob/main/go_router/example/lib/async_data.dart)
for the full details.
