Inject props to your react component.
npm i react inversify react-inject-props --save
or
yarn add react inversify react-inject-props
with typescript, you should install the "reflect-metadata" package as well:
npm i reflect-metadata --save
or yarn add reflect-metadata
- get decorators
- inject
- hierarchical injection
- useExisting
- get container from props
- use ContainerContext directly
you can create decorators InjectProps
and ProvideProps
use createPropsDecorators
function with a inversify container instance as the root container:
import { Container } from 'inversify';
import { createPropsDecorators } from 'react-inject-props';
const container = new Container();
const {InjectProps, ProvideProps, containerManager} = createPropsDecorators(container);
if rootContainer not specified, createPropsDecorators
will create it internally, you can take it from the function result:
import { createPropsDecorators } from 'react-inject-props';
const {InjectProps, ProvideProps, containerManager} = createPropsDecorators();
const rootContainer = containerManager.rootNode.container;
import { injectable } from 'inversify';
import React from 'react';
import { render } from 'react-dom';
@injectable()
class Service {
greeting () {
console.log('hello world');
}
}
// or simply
// @ProvideProps([
// Service
// ])
@ProvideProps([
{provide: Service, useClass: Service}
])
export class App extends React.Component {
render () {
return ...;
}
}
interface PageProps {
service?: Service;
}
@InjectProps({
service: Service
})
export class Page extends React.Component<PageProps> {
componentDidMount () {
this.props.service!.greeting();
}
...
}
render((
<App>
<Page/>
</App>
), document.getElementById('root'));
in Page
component, we can access Service
instance by this.props.service
, because we bind Service
to container at App
component with ProvideProps
decorator and "Inject" it as this.props.service
by InjectProps
.
interface AppConfig {
siteName: string;
}
const AppConfigToken = Symbol('appConfig');
const appConfig: AppConfig = {
siteName: 'Github'
};
@ProvideProps([
{provide: AppConfigToken, useValue: appConfig}
])
export class App extends React.Component {
}
interface PageProps {
appConfig?: AppConfig
}
@InjectProps({
appConfig: AppConfigToken
})
export class Page extends React.Component<PageProps> {
componentDidMount () {
console.log(this.props.appConfig!.siteName);
}
}
@injectable()
class Service {
getConfig () {
return {
siteName: 'Github'
};
}
}
const AppConfigToken = Symbol('appConfig');
function getAppConfig (service: Service) {
return service.getConfig();
}
@ProvideProps([
Service,
{provide: AppConfigToken, useFactory: getAppConfig, deps: [Service]}
])
export class App extends React.Component {
}
interface PageProps {
appConfig?: AppConfig
}
@InjectProps({
appConfig: AppConfigToken
})
export class Page extends React.Component<PageProps> {
componentDidMount () {
console.log(this.props.appConfig!.siteName);
}
}
we can use multiple ProvideProps
decorators in different hierarchies to implement an hierarchical injection system.
@injectable()
class Service {
id = Math.random();
}
@ProvideProps([
Service
])
class App extends React.Component {}
@InjectProps({
service: Service
})
class PageA extends React.Component {}
@InjectProps({
service: Service
})
class CompInPageA extends React.Component {}
@ProvideProps([
Service
])
@InjectProps({
service: Service
})
class PageB extends React.Component {}
render((
<App>
<PageA>
<CompInPageA/>
</PageA>
<PageB/>
</App>
), ...);
in the above example, PageA.props.service
is equals to CompInPageA.props.service
and difference to PageB.props.service
, case PageB is reprovide a Service
.
@ProvideProps([
{provide: Service, useClass: Service, useExisting: true}
])
class Comp extends React.Component { }
render ((
<App>
<Comp/>
</App>
), ...);
if Service
can be resolved in App's providers or rootContainer
, the Service
provider will be ignored.
import { Container } from 'inversify';
interface CompProps {
container: Container;
}
@ProvideProps([
Service
])
class Comp extends React.Component<CompProps> {
componentDidMount () {
const {container} = this.props;
...
}
}
container of current component's hierarchy will also inject in component.props when use ProvideProps
or InjectProps
decorator.
import { ContainerContext } from 'react-inject-props';
// or
import { createPropsDecorators } from 'react-inject-props';
const {ContainerContext} = createPropsDecorators();
// then use it in your component
class Comp extends React.Component {
render () {
return (
<ContainerContext.Provider value={xxx}>
...
...
<ContainerContext.Consumer>
{(container: Container) => {
...
}}
</ContainerContext.Consumer>
...
...
</ContainerContext.Provider>
);
}
}