#flutter #dart
Вопрос:
Я пытаюсь разобраться в библиотеке блоков, но у меня от этого болит голова.
Я пытаюсь получить названия отелей из API. У меня есть модель и служба, ответственная за обращение к API и получение данных. Однако я не знаю, как подключить его к библиотеке блоков.
Как только мое приложение запустится, я хочу, чтобы блок извлек данные из API, а затем показал их в приложении.
Вот мой код:
hotel_model.dart
class Hotels {
final List<Hotel> hotels;
Hotels({this.hotels});
factory Hotels.fromJson(Map<String, dynamic> json) {
return Hotels(
hotels: List<Hotel>.from(
json['hotels'].map(
(x) => Hotel.fromJson(x),
),
),
);
}
}
class Hotel {
final String hotelName;
Hotel({this.hotelName});
factory Hotel.fromJson(Map<String, dynamic> json) {
return Hotel(
hotelName: json['name'],
);
}
}
hotel_service.дарт
import 'package:http/http.dart' as http;
abstract class DownloadService {
Future<http.Response> fetchHotels();
}
class HotelService extends DownloadService {
@override
Future<http.Response> fetchHotels() {
final Uri uri = Uri.https('services.lastminute.com', 'mobile/stubs/hotels');
return http.get(uri);
}
}
И вот что я сделал с блоком lib.
hotel_event.дарт
part of 'hotel_bloc.dart';
@immutable
abstract class HotelEvent {}
class OnAppStartEvent extends HotelEvent {}
hotel_bloc.дарт
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:hotels/models/hotel/hotel_model.dart';
import 'package:hotels/services/hotel/hotel_service.dart';
import 'package:meta/meta.dart';
part 'hotel_event.dart';
part 'hotel_state.dart';
class HotelBloc extends Bloc<HotelEvent, HotelState> {
HotelBloc() : super(HotelFinal());
final HotelService hotelService = HotelService();
@override
Stream<HotelState> mapEventToState(
HotelEvent event,
) async* {
if (event is FetchEvent) {
final response = hotelService.fetchHotels();
yield
}
}
}
hotel_state.дарт
part of 'hotel_bloc.dart';
@immutable
abstract class HotelState {
HotelState();
}
class HotelFinal extends HotelState {
final Hotel hotel;
HotelFinal(this.hotel);
Hotel getHotel() {
return hotel;
}
}
Комментарии:
1. Взгляните на библиотеку блоков , чтобы понять основы
2. @quoci Да, я знаю основы, но там много устаревшей информации.
3. Поставьте ожидание в hotelService. fetchHotels(); После этого у вас будут все ваши отели. теперь вы хотите вывести эти данные в состояние, например, ваш HotelFinal -> вывести HotelFinal(ответ)
4. Я рекомендую вам этот пакет . Это довольно удобно, если вы используете блоки.
Ответ №1:
- Прежде всего добавьте
await
в эту строку в своем блоке
final response = await hotelService.fetchHotels();
- возврат
List<Hotel>
из вашейfetchHotels
функции - у вас должен быть
stateful
класс для вашего экрана, и вinitState
нем вы можете создать свой объект блока и вызвать.add
метод на нем - в своем
build
методе оберните виджет сBlocBuilder
помощью обратного вызова и приbuilder
обратном вызове проверьте состояние вашего блока, если состояниеHotelFinal
соответствует возвращению пользовательского интерфейса со списком отелей в объекте состояния.
Ответ №2:
- Будет полезно добавить другое состояние для вашего
HotelState
, когда ваш блок извлекает данные, и даже когда возникает ошибка. например;
part of 'hotel_bloc.dart';
@immutable
abstract class HotelState {
HotelState();
}
class HotelFinal extends HotelState {
final Hotel hotel;
HotelFinal(this.hotel);
Hotel getHotel() {
return hotel;
}
}
class HotelLoading extends HotelState {
HotelLoading();
}
class HotelError extends HotelState {
final String error;
HotelError(this.error);
}
- Вы хотели бы изменить свой
mapEventToState
на что-то вроде этого:
@override
Stream<HotelState> mapEventToState(
HotelEvent event,
) async* {
if (event is FetchEvent) {
yield HotelLoading();
try {
final response = await hotelService.fetchHotels();
// It seems like your service doesn't return an hotel directly, so you'll have to deal with this as it is not part of the question.
final hotel = getYourHotelHereWithTheResponse;
yield HotelFinal(hotel);
} catch (e) {
yield HotelError('something went wrong getting the hotel info');
}
}
}
- Наконец, добавьте виджет в дерево
FetchEvent
виджетов, который добавляет к вашему блоку, и добавьте aBlocBuilder
, чтобы реагировать на изменение состояний. Обратите внимание, что это очень гибко и может быть сделано многими способами, но это выходит за рамки вашего очень широкого вопроса, я просто показываю вам, как использовать библиотеку минимально:
class MyStatefulWidget extends StatefulWidget {
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
HotelBloc hotelBloc;
@override
void initState() {
hotelBloc = HotelBloc..add(FetchEvent());
super.initState();
}
@override
void dispose() {
hotelBloc.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocBuilder(builder: (context, state) {
if(state is HotelLoading) {
// return a widget to deal with loading
}
if(state is HotelFinal) {
// return a widget to deal with success
}
if(state is HotelError) {
// return a widget to deal with error
}
});
}
}