CodeBlanks Logo Icon CodeBlanks

Loading state

Show loading and error states with FutureBuilder.

State with FutureBuilder

FutureBuilder watches a Future and rebuilds the UI based on the snapshot it provides. You pass the Future to the future parameter and a function taking an AsyncSnapshot to the builder parameter. While waiting you show a loading indicator, and on error you show an error message.

FutureBuilder<Weather>(
  future: weatherFuture,
  builder: (context, snapshot) {
    if (snapshot.hasError) {
      return Text('Hata: ${snapshot.error}');
    }
    return const CircularProgressIndicator();
  },
)

AsyncSnapshot and connection state

AsyncSnapshot carries the state of the Future. You check snapshot.connectionState against ConnectionState.waiting to catch loading, and snapshot.hasData to know whether data has arrived.

builder: (context, snapshot) {
  if (snapshot.connectionState == ConnectionState.waiting) {
    return const CircularProgressIndicator();
  } else if (snapshot.hasError) {
    return Text('Hata: ${snapshot.error}');
  }
  return Text(snapshot.data!.sehir);
}

Practice State handling with FutureBuilder

Write a build method that returns a FutureBuilder<Weather>. While loading show CircularProgressIndicator, on error show Text('Hata'), and when data arrives show Text(snapshot.data!.sehir).

Starter code

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

class Weather {
  final String sehir;
  final double sicaklik;
  Weather(this.sehir, this.sicaklik);
}

// WeatherScreen sınıfını yaz
// build metodu FutureBuilder döndürsün
// yükleme durumunda yükleme göstergesi
// hata durumunda Text('Hata')
// veri geldiğinde sehir alanını göster

void main() {
  print('hazir');
}

Sample solution

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

class Weather {
  final String sehir;
  final double sicaklik;
  Weather(this.sehir, this.sicaklik);
}

class WeatherScreen extends StatelessWidget {
  final Future<Weather> future;
  const WeatherScreen({super.key, required this.future});

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Weather>(
      future: future,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const CircularProgressIndicator();
        } else if (snapshot.hasError) {
          return const Text('Hata');
        }
        return Text(snapshot.data!.sehir);
      },
    );
  }
}

void main() {
  print('hazir');
}

Expected output

hazir

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What is shown while FutureBuilder is loading?

  • The data automatically
  • An empty screen
  • An error message
  • A loading indicator (e.g. CircularProgressIndicator) Correct answer

Explanation: During waiting the connectionState is waiting; you show a loading indicator. Data has not arrived yet, an empty screen is a poor experience, and an error message is shown only when hasError is true.

2 Catch the loading state

Question
builder: (context, snapshot) {
  if (snapshot.connectionState == ____) {
    return const CircularProgressIndicator();
  }
  return Text(snapshot.data!.sehir);
}
Answer
builder: (context, snapshot) {
  if (snapshot.connectionState == ConnectionState.waiting) {
    return const CircularProgressIndicator();
  }
  return Text(snapshot.data!.sehir);
}

Explanation: To catch the waiting state you check ConnectionState.waiting. active, none, and done do not represent loading; done means completed.

3 FutureBuilder parts

Term Meaning
future The Future being watched
builder Function that builds the UI
snapshot.connectionState Connection state
snapshot.hasError Whether there is an error

All lessons in Intermediate