Handle API Lists with Flutter BLoC
Build dynamic Flutter apps by mastering API data fetching.
·
3 min read
Absolutely! Here's a breakdown of how to implement fetching a list from an API in Flutter using the BLoC pattern:
Project Setup
1. Dependencies:
Make sure you have these packages in your pubspec.yaml
file:
dependencies:flutter_bloc: ^8.1.1 # Or the latest versionhttp: ^0.13.5 # Or the latest versionequatable: ^2.0.5 # For easier state comparisons
2. Project Structure: Create a basic structure like this:
lib/bloc/my_api_bloc.dartmy_api_event.dartmy_api_state.dartmodels/my_data_model.dartrepository/my_api_repository.dartmain.dartui/my_data_list_view.dart
Steps
1. Data Model (my_data_model.dart
) Define a model class to represent the list item fetched from your API:
class MyDataModel {final int id;final String name;// Other propertiesMyDataModel({required this.id, required this.name, /* Other properties */});factory MyDataModel.fromJson(Map<String, dynamic> json) {return MyDataModel(id: json['id'],name: json['name']// ...other properties);}}
2. API Repository (my_api_repository.dart
) Create a class to handle the network request:
import 'package:http/http.dart' as http;import 'dart:convert';import '../models/my_data_model.dart';class MyApiRepository {Future<List<MyDataModel>> fetchDataList() async {final response = await http.get(Uri.parse('https://your-api-endpoint'));if (response.statusCode == 200) {final parsed = jsonDecode(response.body).cast<Map<String, dynamic>>();return parsed.map<MyDataModel>((json) => MyDataModel.fromJson(json)).toList();} else {throw Exception('Failed to load data');}}}
3. BLoC (my_api_bloc.dart
)
- Events (
my_api_event.dart
)
Define events to trigger API calls:
abstract class MyApiEvent {}class FetchDataList extends MyApiEvent {}
- States (
my_api_state.dart
)
Define states to represent the UI state:
abstract class MyApiState extends Equatable {}class MyApiInitial extends MyApiState {@overrideList<Object> get props => [];}class MyApiLoading extends MyApiState {@overrideList<Object> get props => [];}class MyApiLoaded extends MyApiState {final List<MyDataModel> dataList;MyApiLoaded(this.dataList);@overrideList<Object> get props => [dataList];}class MyApiError extends MyApiState {final String message;MyApiError(this.message);@overrideList<Object> get props => [message];}
- The BLoC
Handle the events and emit states:
import 'package:flutter_bloc/flutter_bloc.dart';import '../repository/my_api_repository.dart';// ... other importsclass MyApiBloc extends Bloc<MyApiEvent, MyApiState> {final MyApiRepository _repository;MyApiBloc(this._repository) : super(MyApiInitial()) {on<FetchDataList>((event, emit) async {emit(MyApiLoading());try {final dataList = await _repository.fetchDataList();emit(MyApiLoaded(dataList));} catch (e) {emit(MyApiError(e.toString()));}});}}
4. UI (my_data_list_view.dart
)
import 'package:flutter/material.dart';import 'package:flutter_bloc/flutter_bloc.dart';import '../bloc/my_api_bloc.dart';class MyDataListPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Data List')),body: BlocProvider(create: (_) => MyApiBloc()..add(FetchDataList()), // Fetch data on initializationchild: BlocBuilder<MyApiBloc, MyApiState>(builder: (context, state) {if (state is MyApiInitial) {return Center(child: Text('Initial state'));} else if (state is MyApiLoading) {return Center(child: CircularProgressIndicator());} else if (state is MyApiLoaded) {return ListView.builder(itemCount: state.dataList.length,itemBuilder: (context, index) {final data = state.dataList[index];return ListTile(title: Text(data.name),subtitle: Text('ID: ${data.id}'),);},);} else if (state is MyApiError) {return Center(child: Text('Error: ${state.message}'));} else {return Container(); // Unreachable state}},),),);}}
Explanation
BlocProvider
: Provides yourMyApiBloc
instance to the UI tree.BlocBuilder
: Reactively rebuilds a portion of the UI based on your BLoC's state.- State Handling:
MyApiInitial
: Display a placeholder if needed. MyApiLoading
: Show a loading indicator.MyApiLoaded
: Build the list using aListView.builder
.MyApiError
: Display an error message.
Key Points
- The
..add(FetchDataList())
in theBlocProvider
will trigger the API call when the UI initializes. - Customize the way you display your data (the
ListTile
is just a basic example). - Consider how you want to handle refreshing the data (you might add a refresh button or pull-to-refresh functionality).
No comments yet. Login to start a new discussion Start a new discussion