vessel

Creator: coderz1093

Last updated:

0 purchases

vessel Image
vessel Images
Add to Cart

Description:

vessel

IoC-Container for Dart and Flutter
Navigation #

How is it different from Riverpod?
How is it different from GetIt?
Getting started
Features

Providers

Injecting providers
Disposing providers


Overrides

Example


Scopes

Dependencies*




Is it production ready?
Credits

How is it different from Riverpod? #

It's not a state management solution
Only 2 provider types
No need to specify dependencies to achieve correct scoping

How is it different from GetIt? #

Type-safe factories (no more param1 and param2)
Providers are registered at compile-time
Ability to register the same type twice or more in type-safe manner.

Getting started #
Define provider as global variable
class Counter {
final int count = 0;
}

final counterProvider = Provider((read) => Counter());
copied to clipboard
Create container - it holds all providables
final container = ProviderContainer();
copied to clipboard
Read provider
void main() {
/// Counter is created lazily and cached inside container
final counter = container.read(counterProvider);
final sameCounter = container.read(counterProvider);

print(counter == sameCounter); // true
print(counter.count); // 0
}
copied to clipboard
Features #
Providers #
There are 2 types of Providers in vessel:
class Counter {}
class UserViewModel {
final int userId;
UserViewModel(this.userId);
}

// Provider
final counterProvider = Provider((_) => Counter());

// Factory provider
final userVmProvider = Provider.factory(
(_, int userId) => UserViewModel(userId),
);
copied to clipboard
The difference between these two is that Provider.factory creates providers, while usual providers are self-contained.
Consider Provider usage:
container.read(counterProvider); // Counter instance
copied to clipboard
And Provider.factory:
final user100Provider = userVmProvider(100);
container.read(user100Provider);
copied to clipboard
or just:
container.read(userVmProvider(100)) // UserVM.userId === 100
copied to clipboard
Injecting providers
final cartRepositoryProvider = Provider(
(_) => CartRepository(),
);

final cartViewModelProvider = Provider.factory((read, int cartId) {
final repository = read(cartRepository);
return CartViewModel(
repository: repository,
cartId: cartId,
);
});
copied to clipboard
Disposing providers
final cartViewModelProvider = Provider(
(read) => CartViewModel(...),
dispose: (CartViewModel vm) => vm.dispose(),
);
copied to clipboard
Container has dispose method, which disposes all providers within it.
container.dispose();
copied to clipboard
Overrides #
You can override any provider with any other provider of compatible type.
final container = ProviderContainer(
overrides: [
userRepositoryProvider.overrideWith(mockUserRepositoryProvider)
]
);

container.read(userRepositoryProvider); // MockUserRepository
copied to clipboard
Example
Consider this:
class UserRepository {
User getById(int id) {
return User(id: id, isAdmin: false);
}
}

class UserProfileViewModel {
final UserRepository repository;
final int userId;

UserProfileViewModel({
required this.repository,
required this.userId,
});

String get isAdmin => repository.getById(userId).isAdmin;
}

final userRepositoryProvider = Provider(
(_) => UserRepository(),
);

final userProfileVmProvider = Provider.factory(
(read, int userId) => UserProfileViewModel(
userId: userId,
repository: read(userRepositoryProvider),
)
);
copied to clipboard
Here is the task: mock UserRepository, so getById always returns admin user.
Easy:
class MockUserRepository implements UserRepository {
User getById(int id) {
return User(id: id, isAdmin: true);
}
}


final mockRepositoryProvider = Provider<UserRepository>(() => MockUserRepository());

final containerWithOverride = ProviderContainer(
overrides: [
userRepositoryProvider.overrideWith(mockRepositoryProvider),
],
);


void main() {
final profileVm = containerWithOverride.read(userProfileVmProvider(1));
print(profileVm.isAdmin); // true
}
copied to clipboard
Scopes #
Providers can be scoped:
final userProvider = Provider((_) => User(...));
final containerRoot = ProviderContainer();
final containerChild = ProviderContainer(
overrides: [userProvider.scope()],
parent: containerRoot,
);

void main() {
final rootUser = containerRoot.read(userProvider);
final childUser = containerChild.read(userProvider);

identical(rootUser, childUser); // false
}
copied to clipboard
provider.scope() is essentially the same as provider.overrideWith(provider), so scoping and overriding are basically the same thing.
Provider becomes scoped, if any of its dependencies* gets scoped.
Consider this example:
class Counter {
final int count;
Counter(this.count);
}

final provider1 = Provider((_) => Counter(1));
final provider2 = Provider((read) => Counter(read(provider1).count + 1));
final provider3 = Provider((read) => Counter(read(provider2).count + 3));


final container = ProviderContainer();
final containerChild = ProviderContainer.scoped(
[provider2],
parent: container,
);

void main() {
// now provider3 also scoped inside containerChild
final instance3 = containerChild.read(provider3);
final rootInstance3 = container.read(provider3);

identical(instance3, rootInstance3); // false


final instance1 = containerChild.read(provider1);
final rootInstance1 = container.read(provider1);

// provider1 doesn't have scoped dependencies, so it doesn't become scoped.
identical(instance1, rootInstance1); // true
}
copied to clipboard
Dependencies*
final provider1 = Provider((_) => Counter(1));
final provider2 = Provider((read) => Counter(read(provider1).count + 1));
final provider3 = Provider((read) => Counter(read(provider2).count + 3));
copied to clipboard

provider1 has no dependencies
provider2 has single dependency - on provider1.
provider3 has 2 dependencies:



direct dependency on provider2
transitive dependency on provider1 through provider2


Is it production ready? #
Not enough testing have been done to consider this production ready.
But I'm going to use it on production project.
Credits #
The whole project inspired by riverpod, created by Remi Rousselet and community.

License

For personal and professional use. You cannot resell or redistribute these repositories in their original state.

Files In This Product:

Customer Reviews

There are no reviews.