← Назад к вопросам

Что такое FutureBuilder?

1.3 Junior🔥 161 комментариев
#Flutter виджеты#Асинхронность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

FutureBuilder - виджет для работы с асинхронными операциями

FutureBuilder - это виджет, который строит UI на основе состояния Future. Это стандартный способ отображения результатов асинхронных операций (загрузка данных, API запросы).

Базовая структура

FutureBuilder<String>(
  future: fetchData(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator();
    } else if (snapshot.hasError) {
      return Text("Error: ${snapshot.error}");
    } else if (snapshot.hasData) {
      return Text("Data: ${snapshot.data}");
    }
    return Text("No data");
  },
)

Состояния ConnectionState

ConnectionState.none - Future еще не начал выполняться ConnectionState.waiting - Future в процессе (показываем loader) ConnectionState.active - Stream активен (для StreamBuilder) ConnectionState.done - Future завершен (показываем результат)

Практические примеры

Загрузка данных с API:

Future<List<Post>> fetchPosts() async {
  final response = await http.get(Uri.parse("https://api.example.com/posts"));
  if (response.statusCode == 200) {
    return Post.fromJsonList(jsonDecode(response.body));
  } else {
    throw Exception("Failed to load posts");
  }
}

FutureBuilder<List<Post>>(
  future: fetchPosts(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return Center(child: CircularProgressIndicator());
    } else if (snapshot.hasError) {
      return Center(child: Text("Error: ${snapshot.error}"));
    } else if (snapshot.hasData) {
      return ListView.builder(
        itemCount: snapshot.data!.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(snapshot.data![index].title),
          );
        },
      );
    }
    return Center(child: Text("No data"));
  },
)

Инициализация данных в StatefulWidget:

class UserProfile extends StatefulWidget {
  final int userId;
  const UserProfile({required this.userId});
  
  @override
  State<UserProfile> createState() => _UserProfileState();
}

class _UserProfileState extends State<UserProfile> {
  late Future<User> userFuture;
  
  @override
  void initState() {
    super.initState();
    userFuture = fetchUser(widget.userId);
  }
  
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<User>(
      future: userFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Scaffold(
            appBar: AppBar(title: Text("Loading...")),
            body: Center(child: CircularProgressIndicator()),
          );
        } else if (snapshot.hasError) {
          return Scaffold(
            appBar: AppBar(title: Text("Error")),
            body: Center(child: Text("${snapshot.error}")),
          );
        } else if (snapshot.hasData) {
          return Scaffold(
            appBar: AppBar(title: Text(snapshot.data!.name)),
            body: UserContent(user: snapshot.data!),
          );
        }
        return Scaffold(body: Center(child: Text("No data")));
      },
    );
  }
}

Проверка snapshot данных

builder: (context, snapshot) {
  // Проверка состояния подключения
  if (snapshot.connectionState == ConnectionState.waiting) {
    return LoadingWidget();
  }
  
  // Проверка ошибок
  if (snapshot.hasError) {
    return ErrorWidget(error: snapshot.error);
  }
  
  // Проверка наличия данных
  if (!snapshot.hasData) {
    return EmptyWidget();
  }
  
  // Получение данных (гарантированно не null)
  final data = snapshot.data!;
  return DataWidget(data: data);
}

FutureBuilder vs StreamBuilder

FutureBuilder - для одного результата (Future)

Future<Data> loadOnce() async { ... }

StreamBuilder - для множественных результатов (Stream)

Stream<Data> streamData() async* {
  while(true) {
    yield fetchData();
    await Future.delayed(Duration(seconds: 1));
  }
}

Проблемы и решения

Проблема: FutureBuilder создается каждый раз

// Плохо - Future создается при каждом build
FutureBuilder<Data>(
  future: fetchData(),  // Новый Future каждый раз!
  ...
)

// Хорошо - Future создается один раз в initState
class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late Future<Data> _future;
  
  @override
  void initState() {
    super.initState();
    _future = fetchData();
  }
  
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Data>(
      future: _future,
      ...
    );
  }
}

Best Practice

  • Создавай Future в initState для StatefulWidget
  • Всегда обрабатывай все состояния (waiting, error, data)
  • Используй snapshot.hasError для проверки ошибок
  • Используй snapshot.data! только после проверки hasData
  • Для сложного состояния используй BLoC или Riverpod

FutureBuilder - стандартный и удобный способ работы с асинхронными операциями во Flutter.

Что такое FutureBuilder? | PrepBro