Skip to content

Instantly share code, notes, and snippets.

@Tylerian
Created October 19, 2019 13:49
Show Gist options
  • Save Tylerian/b4e3b0961a939ce1904d8902b714f832 to your computer and use it in GitHub Desktop.
Save Tylerian/b4e3b0961a939ce1904d8902b714f832 to your computer and use it in GitHub Desktop.
ViewModel Pattern for React
import React, {
useEffect,
useMemo
} from "react";
import {
ExampleComponentViewModel
} from "./example-component.viewmodel";
type ExampleComponentProps = {
};
function ExampleComponent(props: ExampleComponentProps) {
const vm = useViewModel(ExampleComponentViewModel);
useEffect(() => {
vm.outputs.printLog.subscribe(
value => console.log("[rx] -- ", value)
);
vm.inputs.componentDidLoad();
return () => {
vm.inputs.componentDidUnload();
};
}, [vm]);
return (
<div>
Example Component
</div>
);
}
export {
Footer
};
import {
Subject,
Observable,
BehaviorSubject
} from "rxjs";
import {
map,
withLatestFrom
} from "rxjs/operators";
import {
useViewModel
} from "use-view-model";
type ExampleComponentViewModelType = Readonly<{
inputs: ExampleComponentViewModelInputs;
outputs: ExampleComponentViewModelOutputs;
}>;
type ExampleComponentViewModelInputs = Readonly<{
componentDidLoad: () => void;
componentDidUnload: () => void;
}>;
type ExampleComponentViewModelOutputs = Readonly<{
printLog: Observable<String>;
}>;
class ExampleComponentViewModel
implements
ExampleComponentViewModelType,
ExampleComponentViewModelInputs,
ExampleComponentViewModelOutputs {
printLog: Observable<string>;
get inputs(): ExampleComponentViewModelInputs {
return this;
}
get outputs(): ExampleComponentViewModelOutputs {
return this;
}
constructor() {
const textSbjct = new BehaviorSubject(
"Lmao hacky wacky rx"
);
this.printLog = this.componentDidLoadSubject.pipe(
withLatestFrom(textSbjct),
map(value => value[1])
);
}
private componentDidLoadSubject: Subject<void> = new Subject();
componentDidLoad() {
this.componentDidLoadSubject.next();
}
private componentDidUnloadSubject: Subject<void> = new Subject();
componentDidUnload() {
this.componentDidUnloadSubject.next();
}
}
export {
ExampleComponentViewModel
};
import {
useRef
} from "react";
type ViewModelClassType<T> = { new(): T };
function useViewModel<T>(vmClass: ViewModelClassType<T>): T {
return useRef(new vmClass()).current;
}
export {
useViewModel,
useViewModel as default
};
@monsoir
Copy link

monsoir commented Apr 17, 2023

Hi.

Recently I've use the useRef for holding the viewModel during the component lifetime, too.

However, I find that the viewModel gets created every time the component gets re-rendered.

Would useMemo be a better choice?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment