Use tip: At first, you'll have to install Pulse-Xpackage. Here's the installation tip.
Usage
Pulse-X gives you full control of Future data with PulseXFutureViewModel, PulseXFutureBuilder, PulseXState and PulseXReactions.
PulseXFutureViewModel gives you features such as api handling, api data state control and business logic which are separated from UI.
PulseXFutureBuilder makes UI reactive. It takes view model and builder function as parameters. You can show various widgets based on Future State which can be called via viewModel.status.
PulseXState is a simple class that has four states - initial,loading, loaded,error. You can control each of them.
PulsXeReactions are side effects inspired from Mobx state management. In Pulse, you can only use side effects with Future data. 🥲
Then, create an abstract service class so that you can easily attach, detach and switch concrete services.
import 'package:http/http.dart' as http;
import 'package:posts/model/post.dart';
const String baseUrl = 'https://dummyjson.com';
abstract class ApiService {
final http.Client client = http.Client();
final postUrl = Uri.parse('$baseUrl/posts');
Future<List<Post>> getPosts();
}
After that, create a concrete service class that extends ApiService class.
const int okStatusCode = 200;
const int notFoundStatusCode = 404;
class PostService extends ApiService {
@override
Future<List<Post>> getPosts() async {
try {
http.Response res = await client.get(postUrl);
if (res.statusCode == okStatusCode) {
dynamic data = res.body as dynamic;
final jsonData = jsonDecode(data);
List<dynamic> list = jsonData['posts'] as List<dynamic>;
List<Post> posts = [];
for (dynamic d in list) {
posts.add(Post.fromJson(d));
}
return posts;
} else if (res.statusCode == notFoundStatusCode) {
throw Exception('Data not found!');
}
throw Exception('Something went wrong!');
} on HttpException catch (ex) {
throw const HttpException('No internet connection!');
} catch (ex) {
rethrow;
}
}
}
Now, you are ready to create View Model that extends PulseXFutureViewModel.
class PostViewModel extends PulseXFutureViewModel {
final ApiService service;
PostViewModel({required this.service});
@override
void onInit() {
super.onInit();
_fetchPosts();
}
void _fetchPosts() async {
changeState(PulseXState.loading()); // set state to loading
try {
List<Post> posts = await service.getPosts(); // fetch data
changeState(PulseXState.loaded(
posts,
)); // set state to success and pass the data
} catch (ex) {
changeState(PulseXState.error(ex.toString())); // set state to error and return error message
}
}
}
In UI, you have to take care of two things - reactions and future data. First I'll extract widgets as classes to be clear.
Here, I'll show you one thing. If you don't wanna pass your ViewModel down the widget tree, Pulse-X provides you with PulseXStateManager.of<YourViewModel>(context) method.