Open iampato opened 3 years ago
@iampato ,
For Why use locator(GetIt) with cubit
I have a preference for constructor dependency injection because it allows me to switch out implementations whenever I want.
As such, most of the cubits I need to call external services to have dependencies. Usually, three is the minimum.
SignInCubit({
required ApiService apiService,
required HiveService hiveService,
}) : super(SignInState.initial()) {
_apiService = apiService;
_hiveService = hiveService;
}
And maybe a database call. My principle is, I never use a class directly, I do a constructor injection. As such, when I want to use the cubit say in multiple places, it would mean I have to keep initializing 3 classes each time.
So a GetIt
would allow me to do it only once in one place then reuse it all over.
For what if the state change or you want to reset the cubit current state?
When this happens, GetIt
has a handy feature to reset the singleton. In the same manner, I create lazySingleton
, I can resetLazySingleton
to achieve that effect. So I can this on a widget when I am disposing of it.
Afterthought
Had an issue somewhere and I think I can use registerFactory
instead for some things. I had totally forgotten about this.
Just create singleton class for your services if an object is in memory it wont create another one, Because behind the single lazySingletons are just dart singleton why should you add a dependency
Example:
import 'package:http/http.dart' as http;
import 'package:sqlite_clean/model/post_model.dart';
import 'package:sqlite_clean/util/http.dart';
class PostsHttpRepo {
// Setup a singleton
static final PostsHttpRepo _postsHttpRepo = PostsHttpRepo._internal();
factory PostsHttpRepo() {
return _postsHttpRepo;
}
PostsHttpRepo._internal();
HttpClient httpClient = HttpClient();
// Methods
Future<Post> getHttpPost() async {
http.Response response = await httpClient.getRequest(
"top-headlines?country=us&category=business",
);
if (response != null && response.statusCode == 200) {
print(response.body);
final post = postFromJson(
response.body,
);
return post;
} else {
return null;
}
}
}
This is how you register a singleton
// Setup a singleton
static final PostsHttpRepo _postsHttpRepo = PostsHttpRepo._internal();
factory PostsHttpRepo() {
return _postsHttpRepo;
}
PostsHttpRepo._internal();
And in my cubits, i just add it like this
class PostCubit extends Cubit<PostState> {
PostsHttpRepo _postsHttpRepo = PostsHttpRepo(); // as you can see
PostsDbRepo _postsDbRepo = PostsDbRepo();
PostCubit() : super(PostInitial());
Future<void> fetchArticles() async {
try {
Post post = await _postsHttpRepo.getHttpPost();
if (post != null) {
List<Article> articles = post.articles;
emit(PostLoaded(
articles: articles,
message: "",
));
}
} on SocketException {
emit(PostError("is your device online"));
} catch (e) {
emit(PostError(e));
}
}
}
The same with your lazySingletons without adding a package?
And for registering cubit with Get_it as off flutter_bloc 6 and above as long as you have called BlocProvider up in the tree you can always call `context
PostsHttpRepo _postsHttpRepo = PostsHttpRepo(); // as you can see
PostsDbRepo _postsDbRepo = PostsDbRepo();
This is the bit that was my concern. This concern was born during lessons on testing. In Flutter, when running tests, you cannot make network calls in the test environment. As such, if you want to have the same code without having to check whether the app is running in testing, the best route I found in my case was to use constructor injection. Such that, in testing, I can pass in a mock of the API class to return hard-coded dummy data and use the actual implementation in production without adding lines of code in the network implementation to check whether it's in production or testing.
So I can pass in via the constructor PostsHttpRepoMock
in testing and PostsHttpRepo
in the live environment.
The method you suggest is OK. Only that for a scalable use case, I consider this to be the cleanest implementation.
Mockito My repo layer still remains the same because it takes in dart data types are returned dart data types, in this most of my repos take in maps and return dart models. What I will have to mock is my HTTP class
All of the other layers should run smoothly
I would be open to seeing a full implementation of your proposition with tests.
There is a project I wrote test lemme copy the same implementation to the above example on post
Totally does not make sense, since locators are just singletons, what if the state change or you want to reset the cubit currentstate?