In this blog we will learn about how to use State Management in Flutter with Async Redux .
Introduction
Async Redux extends the Redux pattern to handle both synchronous and asynchronous actions, keeping your app’s state predictable.
This guide shows you how to set up a Redux store, dispatch actions, and manage async operations in Flutter for a responsive UI.
Key Features of Async Redux
- Async Support: It integrates async operations into the redux pattern easily.
- Centralised State Management: It ensures that your app state is maintained in a single place, making it easy to manage and debug.
- Efficient UI Updates: Updates the UI efficiently based on state changes.
- Scalable: Works well for large applications with complex state and async operations.
Setting Up the Flutter Project with Async Redux
Let’s start by setting up a new Flutter project and adding the async redux dependency.
Create a New Flutter Project
Add Dependencies:
Open the pubspec.yaml
file and add the async redux package.
1 2 3 4 |
dependencies: flutter: sdk: flutter async_redux: ^3.0.0 # Latest version |
Run the following command to get the packages:
1 |
flutter pub get |
Using Async Redux in the Flutter Application:
App State :
The app state class holds the state of the app, which includes a list of products. Each product has a name
and a count
representing how many items are available.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
class Product { final String name; final int count; Product({required this.name, required this.count}); Product copyWith({String? name, int? count}) { return Product( name: name ?? this.name, count: count ?? this.count, ); } } class AppState { final List<Product> products; AppState({required this.products}); AppState copyWith({List<Product>? products}) { return AppState( products: products ?? this.products, ); } static AppState initialState() { return AppState( products: [ Product(name: "Apple", count: 0), Product(name: "Banana", count: 0), Product(name: "Orange", count: 0), ], ); } @override bool operator ==(Object other) => identical(this, other) || other is AppState && runtimeType == other.runtimeType && products == other.products; @override int get hashCode => products.hashCode; } |
Product Actions :
Actions are dispatched to modify the state. In our case, we have two actions: Increment and Decrement for product counts.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import 'package:async_redux/async_redux.dart'; import 'app_state.dart'; class IncrementProductCountAction extends ReduxAction<AppState> { final int index; IncrementProductCountAction(this.index); @override AppState reduce() { List<Product> updatedProducts = List.from(state.products); updatedProducts[index] = updatedProducts[index] .copyWith(count: updatedProducts[index].count + 1); return state.copyWith(products: updatedProducts); } } class DecrementProductCountAction extends ReduxAction<AppState> { final int index; DecrementProductCountAction(this.index); @override AppState reduce() { List<Product> updatedProducts = List.from(state.products); updatedProducts[index] = updatedProducts[index] .copyWith(count: (updatedProducts[index].count - 1).clamp(0, double.infinity).toInt()); return state.copyWith(products: updatedProducts); } } |
Product Page :
This page will display a list of products and allow users to increment or decrement the product counts using buttons.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
import 'package:async_redux/async_redux.dart'; import 'package:flutter/material.dart'; import 'package:my_async_project/product_action.dart'; import 'app_state.dart'; class ProductPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Product Count App"), ), body: StoreConnector<AppState, List<Product>>( converter: (store) => store.state.products, builder: (context, products) { return ListView.builder( itemCount: products.length, itemBuilder: (context, index) { final product = products[index]; return ListTile( title: Text(product.name), subtitle: Text("Count: ${product.count}"), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.remove), onPressed: () => StoreProvider.dispatch<AppState>( context, DecrementProductCountAction(index), ), ), IconButton( icon: Icon(Icons.add), onPressed: () => StoreProvider.dispatch<AppState>( context, IncrementProductCountAction(index), ), ), ], ), ); }, ); }, ), ); } } |
Main File:
Finally, we will set up the main app and initialise the redux store.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import 'package:async_redux/async_redux.dart'; import 'package:flutter/material.dart'; import 'package:my_async_project/product_page.dart'; import 'app_state.dart'; late Store<AppState> store; void main() { store = Store<AppState>(initialState: AppState.initialState()); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return StoreProvider<AppState>( store: store, child: MaterialApp( home: ProductPage(), ), ); } } |
Output:
State Management in Flutter with Async Redux
Managing state in Flutter can be challenging, especially with async tasks. Async Redux extends the Redux pattern to handle both synchronous and asynchronous actions, ensuring predictable state updates. This guide will show you how to set up a Redux store and manage async operations for a responsive, maintainable Flutter app.
How It Works:
- State: We define an app state class with a list of products, each having a
name
and acount
. The copy with method is used to create a new state object with updated values. - Actions: We create two actions: increment product count action and decrement product count action . These actions modify the
count
of a specific product by index. - Store: The store holds the global app state and handles dispatching actions. It is initialised in the
main.dart
file, where we use the store provider widget to provide access to the store throughout the app. - UI: The product page uses store connector to access the list of products from the store.
Conclusion:
In this example, we managed the state of product counts, allowing users to interact with and update the state of the app by dispatching actions.
This pattern is scalable, and you can easily extend it to manage more complex states or add additional features like network calls or background tasks.
And thanks for reading this blog for related data click here.
You can read more interesting blogs by mobikul .