mobx-view-model
Version:
MobX ViewModel power for ReactJS
84 lines (83 loc) • 3.67 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable sonarjs/no-nested-functions */
import { observer } from 'mobx-react-lite';
import { useContext } from 'react';
import { viewModelsConfig } from '../config/global-config.js';
import { ActiveViewModelContext, ViewModelsContext, } from '../contexts/index.js';
import { useCreateViewModel, } from '../hooks/use-create-view-model.js';
/**
* Creates new instance of ViewModel
*
* [**Documentation**](https://js2me.github.io/mobx-view-model/react/api/with-view-model.html)
*/
export function withViewModel(VM, configOrComponent, configOrNothing) {
if (typeof configOrComponent === 'function' ||
(configOrComponent && configOrComponent.$$typeof !== undefined)) {
const config = configOrNothing ?? {};
return withViewModelWrapper(VM, {
...config,
ctx: {
VM,
generateId: config.generateId,
...config.ctx,
},
}, configOrComponent);
}
else {
const config = configOrComponent ?? {};
const finalConfig = {
...config,
ctx: {
VM,
generateId: config.generateId,
...config.ctx,
},
};
return (Component) => withViewModelWrapper(VM, finalConfig, Component);
}
}
const REACT_MEMO_SYMBOL = Symbol.for('react.memo');
const withViewModelWrapper = (VM, config, OriginalComponent) => {
const processViewComponent = config.config?.processViewComponent ??
config.vmConfig?.processViewComponent ??
viewModelsConfig.processViewComponent;
const wrapViewsInObserver = config.config?.wrapViewsInObserver ??
config.vmConfig?.wrapViewsInObserver ??
viewModelsConfig.wrapViewsInObserver;
let Component = processViewComponent?.(OriginalComponent, VM, config) ?? OriginalComponent;
if (wrapViewsInObserver &&
Component &&
Component.$$typeof !== REACT_MEMO_SYMBOL) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
Component = observer(Component);
}
const reactHook = config.reactHook;
const getPayload = config.getPayload;
const FallbackComponent = config.fallback ?? viewModelsConfig.fallbackComponent;
const ConnectedViewModel = observer((allProps) => {
const viewModels = useContext(ViewModelsContext);
reactHook?.(allProps, config.ctx, viewModels);
const { payload: rawPayload, ...componentProps } = allProps;
const payload = getPayload?.(allProps) ?? rawPayload;
const model = useCreateViewModel(VM, payload, {
...config,
component: ConnectedViewModel,
props: componentProps,
});
const isRenderAllowedByStore = !viewModels || viewModels.isAbleToRenderView(model.id);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const isRenderAllowedLocally = model.isMounted !== false;
const isRenderAllowed = isRenderAllowedByStore && isRenderAllowedLocally;
if (isRenderAllowed) {
return (_jsx(ActiveViewModelContext.Provider, { value: model, children: Component && _jsx(Component, { ...componentProps, model: model }) }));
}
return FallbackComponent ? (_jsx(FallbackComponent, { ...allProps, payload: payload })) : null;
});
if (process.env.NODE_ENV !== 'production') {
ConnectedViewModel.displayName = `ConnectedViewModel(${VM.name}->Component)`;
}
return ConnectedViewModel;
};