I need some really basic dependency injection for a react project in a similar syntactical manner as in C# or Java. Using context or injection through props is not an option. I tried three solutions so far:
However, none of theses solutions worked, which raised the questions if there is some sort of configuration issue.
Using Inversify / Inversify-React-Decorators / Rect.DI
SomeService.ts
import { inject, injectable } from "inversify";
import { TYPES, ITokenProvider, IFileService } from "../injectables";
import { lazyInject, DIContainer } from "../inversify.config";
export class SomeService {
@inject(TYPES.ITokenProvider) private tokenProvider!: ITokenProvider; //Inversify
//@lazyInject(TYPES.ITokenProvider) private tokenProvider!: ITokenProvider;//Inversify-r-d
//@Inject tokenProvider!: TokenProvider; //react-di
(...)
}
inversify.config.ts
import "reflect-metadata";
import { Container } from "inversify";
import getDecorators from "inversify-inject-decorators";
import { TYPES, ITokenProvider, } from "./injectables";
import { TokenProvider } from "./Services/TokenProvider"
const DIContainer = new Container();
DIContainer.bind<ITokenProvider>(TYPES.ITokenProvider).toConstructor(TokenProvider);
const { lazyInject } = getDecorators(DIContainer, false);
export { DIContainer, lazyInject }
injectables.ts
export interface ITokenProvider {
getSomeToken(): Promise<string>
}
TokenProvider.ts
import "reflect-metadata";
import * as microsoftTeams from "@microsoft/teams-js";
import { injectable } from "inversify";
import { ITokenProvider } from '../injectables';
@injectable()
export class TokenProvider implements ITokenProvider {
public constructor() { }
public async getSomeToken(): Promise<string> {
(...)
}
}
App.tsx (used by react-di instead of inversify.config)
@Module({
providers: [
{ provide: AccessTokenProvider, useClass: AccessTokenProvider },
]
})
Errors
React-DI and Inversify won'r resolve the dependency, causing an undefined error for the property. Inversify decorators causes following error:
TokenProvider.ts:8 Uncaught ReferenceError: Cannot access 'SomeService' before initialization
at Module.SomeService (VM8 main.chunk.js:248)
at Module../src/inversify.config.ts (inversify.config.ts:11)
(...)
Config
tsconfig.json
{
"include": [
"src/*"
],
"compilerOptions": {
"target": "es5",
"jsx": "react",
"allowSyntheticDefaultImports": true,
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"types": [ "reflect-metadata" ]
}
}
I also tried moving the "reflect-metadata"
around different classes.
Nested @lazyInject not working :https://github.com/inversify/InversifyJS/issues/941
The problem exists because of a circular dependency between a class (in the case above, the Header class) and the
inversify.config'.
inversify.configneeds to import
Headerin order to create the bindings but Header needs access to lazy Inject which is createdininversify.config
.The solution is to split your existing i
nversify.config
into three files.Does nothing except create the container (in my case it is called
container.ts
) Imports the container from the previous file and adds the bindings (in my case namedinversify.config.ts
) Imports file 1 (not 2!), calls getDecorators() and exports lazyInject Your class would then import lazyInject from that third file instead ofinversify.config
.