Lightweight and opinionated mvvm glue/helper code for React/Inversify.
This micro-library helps to reduce the aforementioned glue code by trying to make it as easy as possible to connect the two worlds.
You can use
ā ļø
const container = new Container(); // registers all bindings from inversify-inject-decorators container.load(buildProviderModule())
export const App = () => { return (
Motivation
For projects that embrace a MVVM pattern you usually end up writing some glue code to connect your React Components with the designated ViewModel.This micro-library helps to reduce the aforementioned glue code by trying to make it as easy as possible to connect the two worlds.
Dependencies
This library is using inversify as a way to resolve/instantiate the view models, making it a hard dependency. If that is not your taste, feel free to just take the parts you like šInstallation
yarn add inversify-react-mvvm
# or
npm install inversify-react-mvvm
Usage
The ViewModel
All view models have to extendViewModel
. You don't have to implement any of the following methods though, these are for demonstration purposes.provideByClass
is an extension to provide
from inversify-inject-decorators allowing you to register the decorated class by class reference in inversify
. It is not a requirement to do it like that, you can also register your view models explicitely in your container.You can use
provideByClass
not only for ViewModels, but also for your services/etc.ā ļø
provideByClass
registeres the view models as Singleton
.// ExampleViewModel.tsx
import { ViewModel, provideByClass } from 'inversify-react-mvvm';
import { useParams } from 'react-router';
import { inject } from 'inversify';
import { SomeService } from './services/some-service.ts';
@provideByClass
export class ExampleViewModel extends ViewModel {
// you can make full use of property injection
@inject(SomeService) private someService!: SomeService;
public content = "Wow, such empty";
private params!: { id: string };
public _bind = () => {
// by overriding this method you can use hooks/effects/state
this.params = useParams();
}
public onLoad = () => {
console.log('~= componentDidMount');
// place your favorite ajax calls here
}
public onLeave = () => {
console.log('~= componentWillUnmount');
// detach event handlers, dispose, etc.
}
}
The (consumer) component
// Example.tsx
import { ExampleViewModel } from './ExampleViewModel';
import { useVm } from 'inversify-react-mvvm';
export const Example = (props: any) => {
const vm = useVm(MenuViewModel);
return (
<div>{ vm.content }</div>
);
};
The configuration
```tsx // App.tsx (or alike) import { buildProviderModule } from 'inversify-binding-decorators'; import { Container } from 'inversify'; import { BrowserRouter as Router } from 'react-router-dom'; import { InversifyProvider } from 'inversify-react-mvvm';const container = new Container(); // registers all bindings from inversify-inject-decorators container.load(buildProviderModule())
export const App = () => { return (
<InversifyProvider container={container}>
<Router>
<Example />
</Router>
</InversifyProvider>
)
}