DEV Community

Rentyard
Rentyard

Posted on

Building a Small but Powerful Rental Listing App with Flutter + Riverpod

When you start building a real-world rental listing app, things like filtering, asset management (photos/videos), and clean state handling can quickly get complicated.
In this post, I’ll show a practical example of how to build a simple yet scalable architecture using Flutter and Riverpod — clean, testable, and easy to extend.

What We’ll Build

Display a list of rental properties (title, location, price, thumbnail).

Add basic city-based filtering.

Toggle favorites using local state.

Keep the architecture clean with Riverpod instead of Redux-style complexity.

**

Why Riverpod?

**

Simple and predictable.

Test-friendly and easy to compose.

Context-free access (no need for BuildContext).

Works great for both small and large apps.

Code Example

Model:

// models/property.dart
class Property {
final String id;
final String title;
final String city;
final int price;
final String thumbnail;

Property({required this.id, required this.title, required this.city, required this.price, required this.thumbnail});
}

Providers:

// providers/property_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../models/property.dart';

// sample data provider
final propertyListProvider = Provider>((ref) {
return [
Property(id: 'p1', title: 'Cozy 2BR near downtown', city: 'Dhaka', price: 1200, thumbnail: 'https://...'),
Property(id: 'p2', title: 'Sunny studio', city: 'Chittagong', price: 800, thumbnail: 'https://...'),
];
});

final cityFilterProvider = StateProvider((ref) => null);

final filteredPropertyProvider = Provider>((ref) {
final all = ref.watch(propertyListProvider);
final city = ref.watch(cityFilterProvider);
if (city == null || city.isEmpty) return all;
return all.where((p) => p.city.toLowerCase().contains(city.toLowerCase())).toList();
});

UI Widget:

// ui/property_list.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../providers/property_provider.dart';

class PropertyListView extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final properties = ref.watch(filteredPropertyProvider);
return ListView.builder(
itemCount: properties.length,
itemBuilder: (ctx, i) {
final p = properties[i];
return ListTile(
leading: Image.network(p.thumbnail, width: 56, height: 56, fit: BoxFit.cover),
title: Text(p.title),
subtitle: Text('${p.city} • \$${p.price}'),
onTap: () {},
);
},
);
}
}

Production Tips

Use FutureProvider for API calls with loading/error states.

Implement pagination with ListView.builder.

Store favorites in local storage (Hive or SharedPreferences).

Optimize image loading with caching or CDN.

Keep accessibility in mind — proper contrast, alt-text, and semantics.
For more practical examples and rental app case studies, check out Rentyard

Top comments (0)