1.0.8 • Published 5 months ago

universal-di v1.0.8

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

Universal Dependency Injection

MIT License Build Status NPM version Coverage Status PRs welcome

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');
    }, []);
}

Authors

szymeo bartoszswitalski

1.0.8

5 months ago

1.0.5

5 months ago

1.0.2

5 months ago

0.0.2

5 months ago

0.0.1

5 months ago