- Wrapper functions and interfaces for React Hooks API to enable MVVM-like class design.
- <Bind /> component to simplify re-rendering optimization.
- API design to be as concise as possible with high affinity to typescript type checking and IntelliSense.
npm install @jishida/react-mvvm
or
yarn add @jishida/react-mvvm
- react >=16.8.0 || >=17.0.0 || >=18.0.0 or preact >=10.0.0
- typescript >=4.1.0 if needed
import React from 'react';
import ReactDOM from 'react-dom';
import { Bind, observable } from '@jishida/react-mvvm';
const count = observable(0);
function increment() {
count.value += 1;
}
ReactDOM.render(
<Bind $type='button' onClick={increment}>
increment: {count}
</Bind>,
document.getElementById('root')
);
The monitored variable manages its state through an Observable object created from the observable function. Bind component monitors Observable objects passed via props, resolves Observable objects to the component passed in $type prop, then passes the value. Bind component will be re-rendered when Observable objects passed via props is modified or whose notify method is called.
The minimal example is concise, but react-mvvm recommends that you classify states and actions as ViewModel.
import React from 'react';
import ReactDOM from 'react-dom';
import { Bind, observable, proxy } from '@jishida/react-mvvm';
class IncrementViewModel {
count = observable(0);
// proxy function needs to be called after all Observable objects have been created.
state = proxy<IncrementViewModel>(this, 'state');
increment = () => {
this.state.count += 1;
}
}
const store = new IncrementViewModel();
ReactDOM.render(
<Bind $type='button' onClick={store.increment}>
increment: {store.count}
</Bind>,
document.getElementById('root')
);
Direct access to members of Observable objects such as value property is not intuitive and the code does not look good. Therefore, this library recommends using proxy function. proxy function provides six built-in proxies: 'ref', 'value', 'state', 'result', 'error' and 'message'. Those properties are type-safe and can be complemented by IntelliSense, making it more comfortable to code with typescript.
Bind component will be re-rendered when there are changes to the Observable object received from props. It would be easier to understand this Stopwatch Example Demo if you enable the "Highlight updates when components render." option in React Developper Tools. Only components that need to be updated will be re-rendered.
The Observable object can optionally have additional features.
Using ref option, you can add RefObject for React to Observable object and save the code to access the DOM. You can also use validatable and parsable functions instead of observable function to create an object with Validatable interface that extends Observable interface. Validatable objects can be easily validated by specifying a validation or parsing function at initialization, and since they have properties of Observable type such as hasError and errorMessage, the results of validation can be bound to components. validator function creates a ViewModelValidator object, which can be used to manage all Validatable objects belonging to ViewModel by registering instances of ViewModel with it. By registering ViewModel instances with the ViewModelValidator object, ViewModel can manage all Validatable objects at once. In this example, by combining material-ui and these features, a form application is implemented with simple code.
There are two types of builds: full and lite. The lite version of the build does not include proxy, validatable, parsable, and resolveObject functions.
full:
lite:
full:
import ReactMVVM from '@jishida/react-mvvm';
lite:
import ReactMVVM from '@jishida/react-mvvm/lite';
full:
<script crossorigin src="https://unpkg.com/@jishida/react-mvvm@0.3/dist/react-mvvm.min.js"></script>
lite:
<script crossorigin src="https://unpkg.com/@jishida/react-mvvm@0.3/dist/react-mvvm-lite.min.js"></script>
React MVVM supports IE11, but Promise polyfill is required to use async options.
React MVVM is licensed under the Apache 2.0 License