Skip to content

Instantly share code, notes, and snippets.

@hawx1993
Created March 11, 2020 12:59
Show Gist options
  • Select an option

  • Save hawx1993/2ff81fe5475f893133ab213db33fc373 to your computer and use it in GitHub Desktop.

Select an option

Save hawx1993/2ff81fe5475f893133ab213db33fc373 to your computer and use it in GitHub Desktop.
buildContainer
/*
* @Author: trigkit4
* @Date: 2018-09-18 10:07:05
*/
import React, { Component, ComponentType } from 'react';
import { computed, action, observable } from 'mobx';
import { observer } from 'mobx-react';
import _ from 'lodash';
type BuildContainerOptions<T> = {
displayName?: string;
ViewModel: new (...args: any[]) => StoreViewModel;
View: ComponentType<any>;
};
function buildContainer<P = {}, S = {}, SS = any>({
View,
ViewModel,
}: BuildContainerOptions<P>) {
const viewName = View.displayName || View.name;
@observer
class Container extends Component<P, S, SS> {
static displayName = viewName ? `Container(${viewName})` : 'Container';
@observable
vm: any;
View: ComponentType<any>;
constructor(props: P) {
super(props);
this.View = this._createView(View);
this.vm = this._createViewModel(props);
}
componentWillUnmount() {
this.vm.dispose && this.vm.dispose();
}
@computed
private get _viewProps() {
const descriptors = Object.getOwnPropertyDescriptors(this.vm);
const props: any = {};
Object.keys(this.props).forEach((key: string) => {
props[key] = this.props[key];
});
Object.keys(descriptors)
.filter(this._isViewProp)
.forEach((key: string) => {
if (props[key] && props[key] !== this.vm[key]) {
const errorMessage = `buildContainer Error: '${Container.displayName}.props.${key}: ${props[key]}' conflict with '${ViewModel.name}.${key}: ${this.vm[key]}'`;
console.warn(errorMessage);
}
props[key] = this.vm[key];
});
return props;
}
@action
calculateDerivedProps() {
this.vm.getDerivedProps && this.vm.getDerivedProps(this.props || {});
this.vm.onReceiveProps && this.vm.onReceiveProps(this.props || {});
}
private _createView(OriginalView: ComponentType<any>) {
return OriginalView;
}
private _createViewModel(props: any = {}) {
const vm = new ViewModel(props);
vm.getDerivedProps && vm.getDerivedProps(props);
vm.onReceiveProps && vm.onReceiveProps(props);
return vm;
}
private _isViewProp(key: string) {
// - Props start with _ or $ are private
// - 'verboseMemoryLeak' is add by EventEmitter2
// - 'props' don't affect View directly, if you want View response 'props',
// you need to setup a observable/computed prop in ViewModel.
return (
!/^\$|_/.test(key) && key !== 'verboseMemoryLeak' && key !== 'props'
);
}
render() {
this.calculateDerivedProps();
const ContainerView = this.View;
return <ContainerView {...this._viewProps} />;
}
}
return Container;
}
export { buildContainer };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment