Unable to Access This in a Field Initializer to Read 'property" - flutter

I am trying to authenticate a user using bloc pattern and repository. I have also used GetIt to inject some of my dependencies like below:
final getItInstance = GetIt.I;
Future init(){
getItInstance.registerLazySingleton<APIClient>(() => APIClient());
getItInstance.registerLazySingleton<UserRemoteDataSource>(
() => UserRemoteDataSourceImpl(client: getItInstance()));
// commented out previously, getItInstance.registerLazySingleton<UserRepository>(
() => UserRepositoryImpl(dataSource: getItInstance()));
}
and the implementations of the faulty UserRepository classes are:
abstract class UserRepository {
Future<UserModel> loginUser(Map<String, dynamic> body);
Future<UserModel> registerUser(Map<String, dynamic> body);
Future<UserModel> getCurrentUser();
Future<void> logOut();
}
The UserRepositoryImpl class is just a wrapper to implement the above methods and connect with the remote data source via http, so has been omitted. From the DI class, one can easily see the dependencies and dependents, I have omitted them for brevity's sake.
Now, in my auth bloc, I am trying to pass the UserRepository and UserRepositoryImpl to the bloc constructor, to facilitate the api call but I get this error:
lib/presentation/blocs/authentication/authentication_bloc.dart:18:42: Error: Can't access 'this' in a field initializer to read '_repository'.
: _repository = repository, assert(_repository != null),
^^^^^^^^^^^
Here's the bloc constructor:
class AuthenticationBloc
extends Bloc<AuthenticationEvent, AuthenticationState> {
final UserRepository _repository;
AuthenticationBloc(UserRepositoryImpl repository)
: assert(_repository != null), _repository = repository,
super(AuthenticationStateInitial());
... other methods etc
}
Please, what does this mean and how do I rectify it? Thanks

I have realized my mistake, in the constructor, instead of asserting the constructor params to be non null, I was checking for the field value of the repository. Here's the correction from:
final UserRepository _repository;
AuthenticationBloc(UserRepositoryImpl repository)
: assert(**_repository** != null), _repository = repository,
super(AuthenticationStateInitial());
to:
final UserRepository _repository;
AuthenticationBloc(UserRepositoryImpl repository)
: assert(**repository** != null), _repository = repository,
super(AuthenticationStateInitial());
** signifies where the change was made in the two code blocks. Hope it can help someone too.

Related

Singleton with dependency injection in Dart

Can anyone help me with using dependency injection on singleton?
here is my code:
class SpaceController extends ChangeNotifier {
final SpacesPersistence _persistence;
static final SpaceController _instance = SpaceController._internal(persistence: null);
factory SpaceController({required SpacesPersistence persistence}) {
return _instance;
}
SpaceController._internal({required SpacesPersistence persistence}) : _persistence = persistence;
}
abstract class SpacesPersistence {
Future<List<Entry>> getPath();
Future<List<Entry>> getEntries(Entry? parent, [String? keyword]);
Future<List<Connection>> getConnections([List<Entry>? entries]);
Future<void> add(Entry entry);
Future<void> remove(Entry entry);
Future<void> update(Entry entry);
Future<void> setPath(List<Entry> path);
}
This problem is that I want to inject the persistence variable, but _internal requires the argument and _persistence is not ready yet.
Try with passing new instance in _instance. Here SpacesPersistenceImpl is a class which implements SpaceController
class SpaceController extends ChangeNotifier {
final SpacesPersistence _persistence;
static final SpaceController _instance = SpaceController._internal(persistence: SpacesPersistenceImpl());
factory SpaceController() {
return _instance;
}
SpaceController._internal({required SpacesPersistence persistence}) : _persistence = persistence;
}
I simply grab a RiverPod provider, which gives me lazy initialization, discoverability as a singleton, and dependency injection via overrides for mocking during testing. Details at http://riverpod.dev/

Dart: What is the difference when using this keyword and colon after the constructor?

I have found some codes that got me confused regarding "this" keyword and the colon after the constructor.
I want to know what the difference between the two is, and what they are for.
Using colon
class BusinessLogic {
const BusinessLogic({
required DataRepository repository,
}) : _repository = repository;
final DataRepository _repository;
}
Using this keyword
class BusinessLogic {
const BusinessLogic({
required this.repository,
});
final DataRepository repository;
}
In the first sample, _repository is a private member, in the second sample, repository is a public member.
Apart from that, there's no difference, so if you go with public members everywhere, these 2 samples will be equivalent:
class BusinessLogic {
const BusinessLogic({
required DataRepository repository,
}) : repository = repository;
final DataRepository repository;
}
// same as:
class BusinessLogic {
const BusinessLogic({
required this.repository,
});
final DataRepository repository;
}
In Dart, this construction (in the second sample) is called "initializing parameters". You can read more on that here.

Dart freezed same field on all constructors

I'm trying to make a state class for my todo bloc, and I want to keep the loaded todos when I start refreshing. Is there a better way to do this, basically having a mutual field in all the constructors of the class using freezed package
#freezed
class TodoState with _$TodoState {
const factory TodoState.loading(List<Todo> todos) = TodoStateLoading;
const factory TodoState.loaded(List<Todo> todos) = TodoStateLoaded;
const factory TodoState.error(List<Todo> todos, String message) = TodoStateError;
}
I can already use it like this, but i would like to just call state.todos and not having to check for its type:
TodoState state = TodoStateLoaded([/*example*/]);
state.todos // ERROR
(state as TodoStateLoaded).todos // OK
As per this comment freezed do not support super classes. The closest solution that might work for you is this:
// create mixin with getter of properties that you would like to share between states
mixin TodoMixin {
List<Todo> get todos;
}
#freezed
// add mixin to your class with state
class TodoState with TodoMixin, _$TodoState {
const TodoState._(); // add private constructor
//override getter with map function that will return data for each state
#override
List<Todo> get todos {
return map(
loading: (state) => state.todos,
loaded: (state) => state.todos,
error: (state) => state.todos,
);
}
const factory TodoState.loading(List<Todo> todos) = TodoStateLoading;
const factory TodoState.loaded(List<Todo> todos) = TodoStateLoaded;
const factory TodoState.error(List<Todo> todos, String message) = TodoStateError;
}
It will create common getter for state and when you will introduce new state map method will show you, that you need handle new state in getter. Add another property in mixin and you will need override it too.
To use it you can call it in cubit:
state.todos; or in view: context.read<TodoCubit>().state.todos;

Non-nullable instance field '_repository' must be initialized

I'm a beginner in flutter, and trying to follow a tutorial.
I'm stuck in the below error :
I have the below code in chat_service.dart that is used to get an API from Laravel/Mysql :
import 'package:buschat/repository/repository.dart';
class ChatService {
Repository _repository;
ChatService() {
_repository = Repository();
}
getAllChats() async {
return await _repository.httpGet('get-all-chat');
}
}
I'm receiving the following error in ChatService() method:
Non-nullable instance field '_repository' must be initialized.
Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'
The tutorial is working fine, and it's one year old.
You should try....
class ChatService {
Repository _repository = Repository();
ChatService() {
getAllChats();
}
getAllChats() async {
return await _repository.httpGet('get-all-chat');
}
}
Because of null-safety, all variables must be initialized unless they are marked as nullable. So you need to either give a value to your variable or use late keyword which means you need give it value later but you can't use it as null:
late Repository _repository;
or
// not recommended use (you need to use dependency injection)
Repository _repository = Repository();
You can also mark you variable nullable so you can use it as null:
Repository? _repository;

Should I use multiple classes for bloc states or one class with multiple constructors?

I have started learning bloc recently and I noticed some tutorials use multiple classes for states and others just use one class with multiple named constructors.
Example for multiple classes:
abstract class ProductsState {}
class ProductsInitial extends ProductsState {}
class ProductsLoading extends ProductsState {}
class ProductsSuccess extends ProductsState {
final List<Products> products;
ProductsSuccess(this.products);
}
class ProductsError extends ProductsState {
final String error;
ProductsError(this.error);
}
Example for multiple constructors:
enum AuthenticationStates {
initial,
success,
error,
}
class AuthenticationState {
final AuthenticationStates state;
final Authentication model;
final String msg;
const AuthenticationState._(
{this.state = AuthenticationStates.initial,
this.model,
this.msg = ''});
const AuthenticationState.initial() : this._();
const AuthenticationState.success(Authentication mdl)
: this._(model: mdl, state: AuthenticationStates.success);
const AuthenticationState.error(String m)
: this._(state: AuthenticationStates.error, msg: m);
}
Which one is better to use?
In my projects, I use the first way since different state types are clear, you can later build your UI based on that e.g. if (state is ProductsLoading) { show loader }.
You can also generate such classes by using the freezed package (https://pub.dev/packages/freezed). When using it, you would define a single class with different factory constructors (similar to your second option), but the generated code would support the first option you've defined, e.g.:
#freezed
class Union with _$Union {
const factory Union(int value) = Data;
const factory Union.loading() = Loading;
const factory Union.error([String message]) = ErrorDetails;
}
Later, in the UI layer, you could use helper methods like map/maybeMap/when/maybeWhen to build the corresponding view based on state, e.g.:
var union = Union(42);
print(
union.when(
(int value) => 'Data $data',
loading: () => 'loading',
error: (String? message) => 'Error: $message',
),
); // Data 42
I was asking myself the same question.
"The moment you check the concrete type of an instance in your logic, know you're not using polymorphism correctly." - Back in the university.
In the documentation of BloC they use one class with enum in all examples(or extra status class),
the enum will be composed of something similar to SUCCESS FAILURE etc.
Check the PostState mentioned in BloC documentation as example:
https://bloclibrary.dev/#/flutterinfinitelisttutorial?id=post-states
Nevertheless, the multiple sub-classes for state is a commonly used practice among flutter devs. It looks wrong for me, but who knows...