This continuation of previous two blogs on redux flutter. In this we explore more redux tools like how to perform async operations and dev tools.
Middleware
Till now we haven’t seen any async flow in redux. Rather redux principle’s don’t support async flow at all. We need to introduce middleware for this purpose.
Middleware is just simply a piece of code which executes when a action is called. The only difference it doesn’t have to follow redux principles strictly?
To see how to implement a middleware let’s see an example
class LogMiddleware implements MiddlewareClass<AppState> {
@override
void call(Store<AppState> store, dynamic action, NextDispatcher next) {
print("===MIDDLEWARE===");
print(action);
next(action); //very important :)
}
}
So as you can we implement “MiddlewareClass” and override the call function. In your store add your middleware
final store = Store<AppState>(appReducer,
initialState: AppState.fromList(List.from(["Item1", "Item2"])),
middleware: [
LogMiddleware()
]
);
Now what this does is just simply log all actions which are called !! As simple as that.
Next let’s look at async action. Let’s populate our list . Before doing this we need to create a service, model etc which we seen in previous blogs. So i will just put in the code for it.
//services/fetch_list.dart import 'package:flutter_redux_demo/models/item.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'dart:math'; class PostService { static Future<Item> fetchRandomPost() async { var rng = new Random(); var postID = rng.nextInt(100); final response = await http.get('https://jsonplaceholder.typicode.com/posts/$postID'); if (response.statusCode == 200) { // If server returns an OK response, parse the JSON. return Item.fromJson(json.decode(response.body)); } else { // If that response was not OK, throw an error. throw Exception('Failed to load post'); } } }
Next, define out action
class FetchItemAction{
FetchItemAction();
}
Next, this is our middleware
import 'package:flutter_redux_demo/models/item.dart';
import 'package:flutter_redux_demo/redux/actions.dart';
import 'package:flutter_redux_demo/redux/app_state.dart';
import 'package:flutter_redux_demo/service/fetch_list.dart';
import 'package:redux/redux.dart';
class FetchListMiddleware implements MiddlewareClass<AppState> {
@override
void call(Store<AppState> store, dynamic action, NextDispatcher next) {
if (action is FetchItemAction) {
() async {
// store.dispatch(ShowApploading()) we can do something like this as well.
try {
Item item = await PostService.fetchRandomPost();
print("fetched item $item");
store.dispatch(AddItemAction(item));
} catch (e) {
print(e);
//store.dispatch(.. some exception handling ...)
}
}();
}
next(action); // very important :)
}
}
most things are self explanatory.
Next, add a button to fetch call this action, i would be using the FloatingActoinButton
class FetchButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, VoidCallback>(converter: (store) {
return () => store.dispatch(FetchItemAction());
}, builder: (context, cb) {
return FloatingActionButton(
onPressed: () {
cb();
},
child: Icon(Icons.refresh),
);
});
}
}
All done! See full source here https://github.com/excellencetechnologies/flutter_redux_demo/commit/59b3ca48a93799a2e1546adbfd6dde1602fb93b3
Cool! We have setup async calls as well with redux.
At this stage, all basics of Redux Flutter should be fully clear and we can start to develop our original app now again! 🙂
Also few important things before we miss them.
https://pub.dev/packages/flutter_redux_dev_tools
This is a very useful dev tool to debug redux calls. This supports something called as time travel . This is quite useful, and ideally should be used during development in most cases.
Also you can look at this middleware https://github.com/Cretezy/redux_persist to persist data 🙂