To store persistent data in Flutter we can adopt different approaches. Either we can use local storage in key, value pair array; or, we can use SQLite database.
In addition we can use remote database also.
However, the concept revolves around state management, accessorized with Provider package.
The question is, how we can use the state management using Provider package between screens and store persistent data in flutter.
One may ask, why should we use Provider package? We not stateful widget? After all, through stateful widget, we can also store persistent data in flutter.
In addition, stateful widget comes with Flutter, an in-built feature to maintain state.
The one and only answer is, through Provider package we can avoid widget rebuilds. To get the concept, and if you want an evidence please read my previous blog post on stateful vs stateless widgets.
Now, let us start learning how to store persistent data in flutter. At the very beginning, let me tell you, the full code snippet is available in the respective GitHub Repository.
We cannot use full code snippets. As they are too long. Therefore, we must use part of them for brevity.
Above all, we’ll follow MVC or Model-view-controller pattern.
So data comes from the models folder.
import 'package:flutter/foundation.dart';
class Book with ChangeNotifier {
final String id;
final String title;
final String description;
final double price;
final String imageUrl;
bool isFavorite;
Book({
required this.id,
required this.title,
required this.description,
required this.price,
required this.imageUrl,
this.isFavorite = false,
});
void toggleFavoriteStatus() {
isFavorite = !isFavorite;
notifyListeners();
}
}
In the above code, we have defined a Book class whose constructor would pass different properties including a boolean value isFavorite.
We’ve used Dart mixin to use ChangeNotifier, so that we can use ChangeNotifierProvider from provider package.
Now, we must have another data model which is actually our local storage. Based on the product ID, we can retrieve data from that storage.
import 'package:flutter/material.dart';
import 'book.dart';
class Books with ChangeNotifier {
final List<Book> _items = [
Book(
id: 'p1',
title: 'Beginning Flutter With Dart',
description: 'You can learn Flutter as well Dart.',
price: 9.99,
imageUrl:
'https://cdn.pixabay.com/photo/2014/09/05/18/32/old-books-436498_960_720.jpg',
),
Book(
id: 'p2',
title: 'Flutter State Management',
description: 'Everything you should know about Flutter State.',
price: 9.99,
imageUrl:
'https://cdn.pixabay.com/photo/2016/09/10/17/18/book-1659717_960_720.jpg',
),
...
// code is incomplete for brevity
Now, the question is, how we will persist state in flutter?
How do you persist state in Flutter?
To persist state in Flutter, we must place our ChangeNotifierProvider on the top of the Book shopping cart that we’ve been building.
The following code snippet from the main dart file will give you an idea.
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => Books(),
),
ChangeNotifierProvider(
create: (_) => Cart(),
),
ChangeNotifierProvider(
create: (_) => Orders(),
),
],
child: const BookApp(),
),
);
}
class BookApp extends StatelessWidget {
const BookApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Book Shop',
theme: ThemeData(
primarySwatch: Colors.purple,
primaryColor: Colors.deepOrange,
),
home: const BooksOverviewScreen(),
routes: {
BookDetailScreen.routeName: (ctx) => const BookDetailScreen(),
//CartScreen.routeName: (ctx) => CartScreen(),
},
);
}
}
The home page route points to the books overview screen. However, with the help of other controllers we will be able to navigate to the book detail page, or screen.
The home screen will look like this:
![Book App overview in Flutter](https://i0.wp.com/sanjibsinha.com/wp-content/uploads/2021/08/Book-App-overview-in-Flutter.jpg?ssl=1)
Now, in our material design we’ve defined the route, so one click on the image will take us to the respective book detail screen.
![Changed look of product detail page with the help of unique flutter font](https://i0.wp.com/sanjibsinha.com/wp-content/uploads/2021/09/Changed-look-of-product-detail-page-with-the-help-of-unique-flutter-font.jpg?ssl=1)
In our controllers folder, we have two widgets that act as consumers who will listen to the notification sent by the ChangeNotifier.
The following code snippet will give us an idea.
class _BooksOverviewScreenState extends State<BooksOverviewScreen> {
var _showOnlyFavorites = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Book Shop'),
actions: <Widget>[
PopupMenuButton(
onSelected: (FilterOptions selectedValue) {
setState(() {
if (selectedValue == FilterOptions.Favorites) {
_showOnlyFavorites = true;
} else {
_showOnlyFavorites = false;
}
});
},
icon: const Icon(
Icons.more_vert,
),
itemBuilder: (_) => [
const PopupMenuItem(
child: Text('Only Favorites'),
value: FilterOptions.Favorites,
),
const PopupMenuItem(
child: Text('Show All'),
value: FilterOptions.All,
),
],
),
],
),
body: BooksGrid(showFavs: _showOnlyFavorites),
);
}
}
As we can see, the body of the books overview screen points to books grid widget. Therefore, we can have a look at that widget in controllers folder.
@override
Widget build(BuildContext context) {
final productsData = Provider.of<Books>(context);
final products = showFavs ? productsData.favoriteItems : productsData.items;
return GridView.builder(
padding: const EdgeInsets.all(10.0),
itemCount: products.length,
itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
// builder: (c) => products[i],
value: products[i],
child: const BookItem(
),
),
..
// incomplete code for brevity
To persist data, we’ve used Provider.of method which passes context as parameter and uses the type Book class.
Here that plays the crucial role.
final productsData = Provider.of<Books>(context);
Not only that, the following part of the above code also helps us to persist data.
itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
// builder: (c) => products[i],
value: products[i],
child: const BookItem(
),
),
Although the Book App is in primary stage, still it’s worth taking a look at the GitHub Repository.
Moreover, we’ll keep building that e-commerce Book App in the future.
So, stay tuned and get in touch with all Flutter articles that always gives you updated information on Flutter.
Leave a Reply