- all injections by property @inject now.
- @connectBeans now only for react components, otherwise it causes an error;
- @connectBeans now without args;
<BeanProvider>
<App/>
<BeanProvider>
- with decorators:
export const EXAMPLE_SERVICE = "example";
@bean(EXAMPLE_SERVICE)
export default class ExampleService{
doAction = () => "ActionResult"
}
or
bean(EXAMPLE_SERVICE)(ExampleService)
bean("ExampleService1")((beansContext) =>
new ExampleService("init example service 1"));
bean("ExampleService2")((beansContext) =>
new ExampleService("init example service 2"));
this approach allow you to inject dependencies to the constructor
bean("logger")(Logger);
bean("ExampleService")(({getBeanInstance}) =>
new ExampleService(getBeanInstance("logger")));
important: js files should be imported to be added to the chunk
All injections are lazy - Instances are created only if you access to the @inject property.
- to component Wrap your components first with connectBeans or withInject (alias for connectBeans). Then your component will receive function getBeanInstance(beanId) to props, and you can inject beans to it with inject decorator or manually.
@connectBeans
class About extends Component {
@inject(EXAMPLE_SERVICE)
example;
@inject(OTHER_SERVICE)
otherService;
...
componentDidMount(){
const result = this.example.doAction();
this.otherService.someAction(result)
}
...
}
- to other service Injecting to services not requires any wrappers. Main condition - service should contains beanContext property (autofilled on create service)
const ALERT_SERVICE = "alert";
@bean(ALERT_SERVICE)
class AlertService {
@inject("example")
example;
@inject("otherService")
otherService;
postInject(){
//do something after bean injected
}
...
alert = () => {
const result = this.example.doAction();
this.otherService.someAction(result)
}
...
}
You can define which bean will be created depending on the active profile.
- Declare beans for profiles:
@bean(LOGGER)
@profile("debug", "test")
class DebugLogger{
info(...args){
console.log((new Date()).toISOString(), ...args)
}
}
@bean(LOGGER)
@profile("release")
class ReleaseLogger{
info(...args){
//do nothing or send logs
}
}
- Define active profile in BeanProvider
<BeanProvider activeProfile="debug"><App/></BeanProvider>
Keep the decorators in order: @bean @profile class
You can use test profile to define beans (e.g. data mocks)
Jest example:
test('Test bean should be injected from test', () => {
@bean(LOGGER)
@profile("test")
class TestLogger {
logs = [];
info(...args) {
this.logs.push({level: 'info', time: new Date(), message: args});
}
error(...args) {
this.logs.push({level: 'error', time: new Date(), message: args});
}
}
const m = mount(<BeanProvider
activeProfile={"test"}
nonBean={"nonBean"}>
<App/>
</BeanProvider>);
const app = m.find(App).children().instance();
const {logger} = app;
expect(logger.constructor.name).toBe("TestLogger");
console.log(logger.logs);
expect(logger.logs.length).toBeGreaterThan(0);
m.unmount();
});
In some cases you should able to get some bean instance before your app component rendered.
You can create beans context and get bean instance from it. And then pass it to the BeanProvider component.
example:
import config from './config';
import {createBeansContext, BeanProvider} from 'react-beans';
//createBeansContext(predefinedBeanInstances, activeProfile = default)
const beansContext = createBeansContext({config});
const logger = beansContext.getBeanInstance('logger');
logger.info('App started');
ReactDOM.render(
<BeanProvider
beansContext={beansContext}>
<App/>
</BeanProvider>, document.getElementById('root'));
just clone repo & npm i & npm start