-
Notifications
You must be signed in to change notification settings - Fork 2
Home
A library for developing ReactJS applications using Model-View-ViewModel, inspired by .NET.
Model-View-ViewModel, or MVVM for short, is a User Interface architectural pattern first introduced by Microsoft when they published Windows Presentation Foundation. It is one of the best patterns I have worked with when it comes to forms, as well as detail and list pages.
This is an object-oriented approach to managing state on the front-end, this brings more than a heap of knowledge, experience and design patterns from years of software development using this paradigm.
The library provides a few core features essential to any front-end application.
-
Base implementations for events and view models making them available for all types of pages.
-
A form model covering from basic to the most complex cases. Understanding the model can be done incrementally making it easy to get started.
-
A validation model that can be configured for any form component along side validation triggers including more complex scenarios.
-
A dependency resolution mechanism to simplify creation of different objects that are used in different components.
To check the library out and test things see React MVVM on CodeSandbox.
Go to: Overview | Motivation | API | Guides and Tutorials - Getting Started | CodeSandbox
I have worked with both Model-View-ViewModel and Flux-based architectures, mostly Redux, and I was a bit surprised that there is not much interest for MVVM in ReactJS although it is generally aknowledged that it is a very good pattern when it comes to forms.
I wanted to try MVVM out in a ReactJS application, the opportunity for this came on the project where we were using ReduxForm and one of our edit pages is quite large and had to work around ReduxForm's limitations, the UI was stuttering, we have some specific features on our edit pages that were a bit more difficult to add into the ReduxForm state so we have everything together.
One of our forms was very slow, visibly slow, the users had a bad time with it and we tried a number of approaches to fix it using ReduxForm. It got better, but not by much. After these results I wanted to try an MVVM approach and see if that will perform better, and it it. It was stellar compared to what we had previously. One of slowest form has become the fastest, and I do mean the fastest in the entire application, somewhere around a 4x performance improvement. No more stutters, instant validation, it worked great.
I've done most of the implementation for MVVM on my spare time, after testing it and seeing it work that well I've made it into a library which became React MVVM version 1 and after using it on the project I've come to realize its limitations and places where I would like it to be better and here we are with version 3.
The main frustrations I had with ReduxForm, but this applies to other libraries as well as most take the same approach, is the lack of a clear form structure which leads to really poor type safety. The structure of our forms was defined by the components that were mounted, I do not fully understand why as the form itself exists outside the components, like state is outside the components.
The type of values each field had was ambiguous as well, several fields contained strings, others contained numbers and some of them (e.g. people pickers) had objects detailing the selected value.
Validation was another big issue, this is where I took a different approach with React MVVM, instead of validating the entire form each time a single field changes, I added validation triggers. When you configure validation and the validity of one field is determined by the value of another (e.g.: start/end date pair), then you need to specify the dependency as a trigger. If either field changes, then the validation is triggered, if any other field changes then there is no need to revalidate.
The general idea is to minimize code that runs when editing a single field and for the most part I think I managed to do that. There is more to talk about when it comes to validation and form structure, check the API documentation, I've added plenty along side code snippets.
Forms are the most challenging aspect of a front-end application, any library, architectural pattern or approach that allows for good performance, enables type safety and is easy to extend will work for display pages and list views just as good. In my humble opinion, that's where the decider is, your application needs to handle forms well, whatever library or pattern is used there will perform well for any other page in the application as they are less complex.
React MVVM provides all of the above, when you define your form you have a clear structure, it enables type safety as much as possible, extending fields and forms with features is easily done without compromising what was already stated. On top of everything, it is fast. It performs very well from small to large forms.
Go to: Overview | Motivation | API | Guides and Tutorials - Getting Started | CodeSandbox
- IEvent<TSubject, TEventArgs>
- IEventHandler<TSubject, TEventArgs>
- EventDispatcher<TSubject, TEventArgs>
- Form<TValidationError>
- IFormFieldConfig<TValue, TValidationError>
- FormField<TValue, TValidationError>
- ReadOnlyFormCollection<TForm, TValidationError>
- FormCollection<TForm, TValidationError>
- IConfigurableFormCollection<TSection, TValidationError>
- FormSetupCallback<TSection, TValidationError>
- IValidator<TValidatable, TValidationError>
- ValidatorCallback<TValidatable, TValidationError>
- IObjectValidator<TValidatable, TValidationError>
- IValidatable<TValidationError>
- IValidationTriggersSet
- IReadOnlyObjectValidator<TValidatable, TValidationError>
- IReadOnlyValidatable<TValidationError>
- IObjectValidatorConfig<TValidatable, TValidationError>
- ObjectValidator<TValidatable, TValidationError>
- Validatable<TValidationError>
- ValidationTriggerSelector<T>
- ValidationTriggerSet
- ICollectionChangedValidationTriggerConfig<TItem, TCollection>
- CollectionChangedValidationTrigger<TItem, TCollection>
- ICollectionItemValidationTriggerConfig<TItem>
- CollectionItemValidationTrigger<TItem>
- ICollectionReorderedValidationTriggerConfig<TItem, TCollection>
- CollectionReorderedValidationTrigger<TItem, TCollection>
- IMapChangedValidationTriggerConfig<TKey, TItem, TMap>
- MapChangedValidationTrigger<TKey, TItem, TMap>
- IMapItemValidationTriggerConfig<TKey, TItem>
- MapItemValidationTrigger<TKey, TItem>
- ISetChangedValidationTriggerConfig<TItem, TSet>
- SetChangedValidationTrigger<TItem, TSet>
- ISetItemValidationTriggerConfig<TItem>
- SetItemValidationTrigger<TItem>
- IViewModelChangedValidationTriggerConfig<TViewModel>
- ViewModelChangedValidationTrigger<TViewModel>
- resolveAllValidationTriggers
- resolveValidationTriggers
- ReadOnlyObservableCollection<TItem>
- ObservableCollection<TItem>
- INotifyCollectionChanged<TItem>
- CollectionChangeOperation
- INotifyCollectionReordered<TItem>
- CollectionReorderOperation
- ICollectionChangedEvent<TSubject, TItem>
- ICollectionChangedEventHandler<TSubject, TItem>
- ICollectionReorderedEvent<TSubject, TItem>
- ICollectionReorderedEventHandler<TSubject, TItem>
- IObservableCollection<TItem>
- IReadOnlyObservableCollection<TItem>
- ICollectionChange<TItem>
- ICollectionItemMove<TItem>
- ICollectionReorder<TItem>
- ReadOnlyObservableMap<TKey, TItem>
- ObservableMap<TKey, TItem>
- INotifyMapChanged<TKey, TItem>
- MapChangeOperation
- IMapChangedEvent<TSubject, TKey, TItem>
- IMapChangedEventHandler<TSubject, TKey, TItem>
- IObservableMap<TKey, TItem>
- IReadOnlyObservableMap<TKey, TItem>
- IMapChange<TKey, TItem>
- IObservableSet<TItem>
- IReadOnlyObservableSet<TItem>
- ISetChangedEvent<TSubject, TItem>
- ISetChangedEventHandler<TSubject, TItem>
- ISetLike<TItem>
- ISetChange<TItem>
- isSetLike
- IDependencyResolver
- IDependencyContainer
- DependencyContainer
- useDependency
- useViewModelDependency
- useDependencyResolver
- ConfigurableDependency<T>
- DependencyFactoryCallback<T>
- BasicDependency<T>
- ComplexDependency<T, TAdditional>
- ResolvableSimpleDependency<T>
- SimpleDependency<T>
- DependencyToken<T>
- IDependencyResolverProviderProps
- IDependencyResolverScopeProps
- DependencyResolverProvider
- DependencyResolverScope
Go to: Overview | Motivation | API | Guides and Tutorials - Getting Started | CodeSandbox
Overview
Motivation
Guides and Tutorials - Getting Started
Releases
CodeSandbox
API
Events
IEvent
IEventHandler
EventDispatcher
ViewModels
INotifyPropertiesChanged
ViewModel
Forms
Form
IFormFieldConfig
FormField
ReadOnlyFormCollection
FormCollection
IConfigurableFormCollection
FormSetupCallback
Validation
IValidator
ValidatorCallback
IObjectValidator
IValidatable
Validation / Triggers
WellKnownValidationTrigger
ValidationTrigger
Observable Collection
ReadOnlyObservableCollection
ObservableCollection
INotifyCollectionChanged
CollectionChangeOperation
INotifyCollectionReordered
CollectionReorderOperation
Observable Map
ReadOnlyObservableMap
ObservableMap
INotifyMapChanged
MapChangeOperation
Observable Set
ReadOnlyObservableSet
ObservableSet
INotifySetChanged
SetChangeOperation
Dependency Handling
IDependencyResolver
IDependencyContainer
DependencyContainer
useDependency
useViewModelDependency
useDependencyResolver
React Hooks
useViewModel
useViewModelMemo
useObservableCollection
useObservableMap
useObservableSet