Disco
Disco is a library introducing a new concept of providers that operate differently from those already present in the Flutter ecosystem. It was developed to overcome the challenges and limitations in the context of dependency injection.
Usage
-
Create a provider
-
Scope/provide the provider
-
Inject the provider (within the above
ProviderScope
’s subtree)
Trade-offs
Pros
The pros of Disco are:
- The providers are scoped.
- The widget tree is fully leveraged.
- This keeps the architecture simple.
- The widget tree is fully leveraged.
- No global state is possible.
- Circular dependencies are impossible.
- Multiple providers of the same type are possible.
- There is no need to create wrapper types or rely on IDs such as strings.
- The API is very simple and feels natural to Flutter.
- Providers are equipped with
of(context)
andmaybeOf(context)
methods. - All you need is
BuildContext
. There is no additional class needed to inject the providers.
- Providers are equipped with
- The removal of a provider has an impact on its providing and each of its injections.
- Each of them is immediately characterized by a static error.
- The values held by the providers are immutable.
- While immutable, some instances allow for inner mutation.
- This is great: observables and signals can be passed down.
- While immutable, some instances allow for inner mutation.
- No reactivity is included.
- This library focuses on DI, so that state management solutions can focus on the reactivity.
- To include reactivity, provide a built-in or third-party observable/signal to the provider (e.g.
Signal
,ChangeNotifier
,Cubit
, …).
Cons
The cons of this library are:
- Providers might need to be lifted up or down in the widget tree, as requirements change.
- Modals spawn new widget trees, causing disconnection with the providers in the main tree.
- A special widget must be used to restore access to the providers in the main widget tree.
- It is not fully compile-time safe.
- The injection of a provider that cannot be found in any scope results in a runtime error.
In Disco’s defense regarding the last point:
- Total compile-time safety is not possible with an approach leveraging scoped DI, which is a pattern ubiquitously used in Flutter and third-party libraries (think about how many times you have already read
MediaQuery.of(context)
,GoRouter.of(context)
, …). - Disco providers also have a
maybeOf(context)
method, which can help if the presence of a provider cannot be guaranteed. - The throwable includes precise information in its stack trace to deduce the missing provider: filepath, line and column.
Keep in mind
As the authors of Disco, we believe this to be the most effective strategy for DI in Flutter. However, every solution has trade-offs. You can limit the impact of these trade-offs by running tests, doing code reviews, and following other crucial practices.