diff --git a/docs/MVVM.md b/docs/MVVM.md index 6175e21853..756a974391 100644 --- a/docs/MVVM.md +++ b/docs/MVVM.md @@ -8,7 +8,13 @@ General description of the pattern can be found [here](https://en.wikipedia.org/ If you do MVVM right, your view should be dumb i.e it gets data from the view model and merely displays it. -### Practical guidelines for MVVM in element-web +## Why are we using MVVM? + +1. MVVM forces a separation of concern i.e we will no longer have large react components that have a lot of state and rendering code mixed together. This improves code readability and makes it easier to introduce changes. +2. Introduces the possibility of code reuse. You can reuse an old view model with a new view or vice versa. +3. Adding to the point above, in future you could import element-web view models to your project and supply your own views thus creating something similar to the [hydrogen sdk](https://github.com/element-hq/hydrogen-web/blob/master/doc/SDK.md). + +## Practical guidelines for MVVM in element-web A first documentation and implementation of MVVM was done in [MVVM-v1.md](MVVM-v1.md). This v1 version is now deprecated and this document describes the current implementation. @@ -19,12 +25,12 @@ This is anywhere your data or business logic comes from. If your view model is a #### View 1. Located in [`shared-components`](https://github.com/element-hq/element-web/tree/develop/packages/shared-components). Develop it in storybook! -2. Views are simple react components (eg: `FooView`). -3. Views use [useSyncExternalStore](https://react.dev/reference/react/useSyncExternalStore) internally where the view model is the external store. +2. Views are simple react components (eg: `FooView`) with very little state and logic. +3. Views must call `useViewModel` hook with the corresponding view model passed in as argument. This allows the view to re-render when something has changed in the view model. This entire mechanism is powered by [useSyncExternalStore](https://react.dev/reference/react/useSyncExternalStore). 4. Views should define the interface of the view model they expect: ```tsx - // Snapshot is the return type of your view model + // Snapshot is the data that your view-model provides which is rendered by the view. interface FooViewSnapshot { value: string; } @@ -34,16 +40,16 @@ This is anywhere your data or business logic comes from. If your view model is a doSomething: () => void; } - // ViewModel is a type defining the methods needed for `useSyncExternalStore` + // ViewModel is an object (usually a class) that implements both the interfaces listed above. // https://github.com/element-hq/element-web/blob/develop/packages/shared-components/src/ViewModel.ts type FooViewModel = ViewModel & FooViewActions; interface FooViewProps { + // Ideally the view only depends on the view model i.e you don't expect any other props here. vm: FooViewModel; } function FooView({ vm }: FooViewProps) { - // useViewModel is a helper function that uses useSyncExternalStore under the hood const { value } = useViewModel(vm); return (