universal-di v1.0.8
Universal Dependency Injection
Contents
Providing Dependencies
Imagine there is a class called ProductService that needs to act as a dependency in a state.
The first step is to add the @Injectable decorator to show that the class can be injected.
@Injectable()
class ProductState {
}
@Injectable()
class ProductService {
}
Second step is to make it part of your module
@Module({
providers: [
ProductState,
ProductService
],
})
class ProductModule {
}
and then provide to your React DOM
const application = new DIApplication(ProductModule);
<DIContextProvider
injector={application.rootInjector}
>
<ProductListComponent />
</DIContextProvider>
Once you register a provider, you will get singleton instance of this service every time you'd try to inject it.
Injecting a Dependency
Registered provider can be injected into a class from the same @Module
@Injectable()
class ProductState {
constructor(private productService: ProductService) {
}
}
or directly into the React component
// ProductListComponent.tsx
const productState = useInjection(ProductState);
Besides being a singleton, class is instantiated only when injected, not before.
Advanced usage
Imagine you are tracking events differently depending on environment
interface AnalyticsService {
track(event: string): void;
}
const ANALYTICS_SERVICE = new InjectionToken<AnalyticsService>('ANALYTICS_SERVICE')
After defining the abstraction, next step will be to define implementations
@Injectable()
class RealAnalyticsService implements AnalyticsService {
constructor(
@Inject(TRACKING_API_URL) private readonly _trackingApiUrl: string,
private readonly _httpClient: HttpClient,
) {
}
track(event: string): void {
this._httpClient.post<void>(this._trackingApiUrl);
}
}
@Injectable()
class ConsoleAnalyticsService implements AnalyticsService {
track(event: string): void {
console.log('[tracking]', event);
}
}
Put together in a @Module
const TRACKING_API_URL = new InjectionToken<string>('TRACKING_API_URL');
@Module({
providers: [
{
provide: ANALYTICS_SERVICE,
useClass: isDev() ? ConsoleAnalyticsService : RealAnalyticsService,
},
{
provide: TRACKING_API_URL,
useValue: '/api/track',
}
],
})
class AnalyticsModule {
}
@Module({
imports: [
AnalyticsModule,
],
providers: [
HttpClient,
]
})
class ProductModule {
}
Provide to React
const application = new DIApplication(ProductModule);
<DIContextProvider
injector={application.rootInjector}
>
<ProductListComponent />
</DIContextProvider>
And use
export function ProductListComponent() {
const analyticsService = useInjection(ANALYTICS_SERVICE); // AnalyticsService type is inferred here
useEffect(() => {
analyticsService.track('browsed-productes');
}, []);
}