Skip to content

Instantly share code, notes, and snippets.

@jouana
Last active April 12, 2021 16:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jouana/43b4d654ad47753632f1ea334fecc589 to your computer and use it in GitHub Desktop.
Save jouana/43b4d654ad47753632f1ea334fecc589 to your computer and use it in GitHub Desktop.
React MVVM example
function BindingHook({ dataContext, path, mode }) {
const [data, setData] = useState(dataContext[path]);
useEffect(() => {
onPropertyChanged = (newData) => {
setData(newData);
};
dataContext.subscribeOnPropertyChanged(path, onPropertyChanged);
return () => { dataContext.unsubscribeOnPropertyChanged(path, onPropertyChanged); }
});
return mode.onWay
? data
: {
onChange: (event) => {
dataContext[path] = event.target.value;
},
value: data
};
}
class FriendViewModel extends ViewModelBase {
_personalId;
_friend;
constructor(personalId, friend) {
this._personalId = personalId;
this._friend = friend;
}
delete() {
personalService.removePresonalFriend(this.personalId, this._friend)
}
get name () {
return this._friends.name;
}
}
export default ({ id }) => {
const viewModel = new PersonalViewModel(id);
useEffect(() => {
viewModel.onLoad();
});
return (<div>
<h1>
{
Binding({
dataContext: viewModel,
path: "fullName",
mode: ViewModelMode.OneWay
})
}
</h1>
<input {...Binding({dataContext: viewModel, path: "age", mode: ViewModelMode.TwoWay})}
<table>
{
viewModel.friends.Map(tableFriendLineBuilder)
}
</table>
</div>);
}
function tableFriendLineBuilder(friendViewModel) {
return (<tr>
<td>{Binding({dataContext: viewModel, path: "name", mode: ViewModelMode.OneWay})}</td>
<td><button onclick={friendViewModel.delete}></td>
<tr>);
}
class PersonalViewModel extends ViewModelBase {
_id;
_data;
_friends;
constructor(id) {
this._id = id
}
onLoad() {
this._data = personalService.find(this.id);
this._friends = this._data.friends.map(friend => new FriendViewModel(friend));
}
get fullName () { return this._data && `${this._data.firstName} ${this._data.lastName}`; }
get age () {
return this._data.age;
}
set age (value) {
this._data.age = value;
this.raisePropertyChanged("age");
this.raisePropertyChanged("isMajor");
}
get isMajor() {
return this._data.age > 17;
}
get friends () {
return this._friends;
}
}
class ViewModelBase {
handlers;
subscribeOnPropertyChanged(path, handler) {
if(!this.handlers[path]) {
this.handlers[path] = [];
}
this.handlers[path].push(handler);
}
unsubscribeOnPropertyChanged(path, handler) {
this.handlers[path].splice(this.handlers[path].indexOf(handler), 1);
}
raisePropertyChanged(path) {
data = this[path];
this.handlers[path].forEach(handler => handler(data));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment