I have a react-native application frontend using inversify-js.
I've structured some service classes to use IOC (using an inversify container), such services intended to be shared as just one singleton instances among other services. They have an init/destroy method to help to clear up the services' internal state.
The init/destroy mechanism works fine but on top of that, it would be nice to have a way to "clear" the inversify container singletons, to rebuild all my singleton services from scratch.
Example:
src/services/A.ts
@injectable()
export class A extends Service {
constructor() {
super();
}
init() {
super.init();
// [...] Initialize A's state
}
destroy() {
// [...] Destroy A's state
super.destroy();
}
method() {
// [...] Provide functionality to other services (maintaining A's state)
}
}
src/services/B.ts
@injectable()
export class B extends Service {
constructor(
b: B // receive injected instance of service A using constructor injection (inversify)
) {
super();
}
init() {
super.init();
// [...] Initialize B's state
}
destroy() {
// [...] Destroy B's state
super.destroy();
}
method() {
// [...] Provide functionality to other services (maintaining B's state, using also service A)
this.a.method();
}
}
src/inversify/container.ts
export const containerModule = new ContainerModule((bind) => {
// Services
bind<A>(A).toSelf().inSingletonScope();
bind<B>(B).toSelf().inSingletonScope();
});
const container = new Container();
container.load(containerModule);
export default container;
index.ts
let a = container.get<A>(A);
let b = container.get<A>(B);
// [...] use services
// Destroy services (es: logout/reload app)
a.destroy();
b.destroy();
// Here I'd also like to "reset" the container
// container.reset(); // like this?
// [...] After some time (maybe login again?)
// I'd like these two to be new singleton instances (!== from previous a,b)
a = container.get<A>(A);
b = container.get<A>(B);
I should be able to maybe "unload" the ContainerModule from the Container (container.unload(containerModule)
) and "load" it again? Seems hacky though, I was looking for comparable solutions.
I looked into this question but, in the end, didn't need the same "reset" functionality anyway: Reset scoped container in inversifyjs
The solution I suggest in the other answer is to simply ditch the current container
and create a fresh instance, very clean and easy to understand.
But then I look into the source code and find that such feature is already included.
container.unbindAll()
it is!
This API unconditionally resets the container to a fresh state (almost fresh, explain later) without the need to create a new instance. Link to source code.
I said "almost fresh" earlier, this is because container also has a less known (at least to me) feature called snapshots. Turns out you can even have multiple snapshots of binding setups stored in one container.
Interesting 🤔. So if you make a snapshot of a empty container before registering any binding, and restore it later, it’s effective a "reset".
Lastly, container.unload(containerModule)
is totally valid, not hacky at all. May call this one selective reset 😂
If you read the source code you’ll see, under the hood of all these methods, it’s all about modifying the internal _bindingDictionary
. That’s where all the bindings are stored.