mobx-view-model
Version:
MobX ViewModel power for ReactJS
108 lines (107 loc) • 3.7 kB
JavaScript
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable react-hooks/rules-of-hooks */
import { useContext, useLayoutEffect } from 'react';
import { viewModelsConfig } from '../config/global-config.js';
import { ActiveViewModelContext } from '../contexts/active-view-context.js';
import { ViewModelsContext } from '../contexts/view-models-context.js';
import { useIsomorphicLayoutEffect } from '../lib/hooks/use-isomorphic-layout-effect.js';
import { useValue } from '../lib/hooks/use-value.js';
import { generateVmId } from '../utils/generate-vm-id.js';
import { isViewModelClass } from '../utils/typeguards.js';
/**
* Creates new instance of ViewModel
*
* [**Documentation**](https://js2me.github.io/mobx-view-model/react/api/use-create-view-model.html)
*/
export function useCreateViewModel(VM, payload, config) {
if (isViewModelClass(VM)) {
// scenario for ViewModelBase
return useCreateViewModelBase(VM, payload, config);
}
// scenario for ViewModelSimple
return useCreateViewModelSimple(VM, payload);
}
const useCreateViewModelBase = (VM, payload, config) => {
const viewModels = useContext(ViewModelsContext);
const parentViewModel = useContext(ActiveViewModelContext) || null;
const ctx = config?.ctx ?? {};
const instance = useValue(() => {
const id = viewModels?.generateViewModelId({
...config,
ctx,
VM,
parentViewModelId: parentViewModel?.id,
}) ??
config?.id ??
generateVmId(ctx);
const instanceFromStore = viewModels ? viewModels.get(id) : null;
if (instanceFromStore) {
return instanceFromStore;
}
else {
const configCreate = {
...config,
vmConfig: config?.config ?? config?.vmConfig,
id,
parentViewModelId: parentViewModel?.id,
payload: payload ?? {},
VM,
viewModels,
parentViewModel,
ctx,
};
viewModels?.processCreateConfig(configCreate);
const instance = config?.factory?.(configCreate) ??
viewModels?.createViewModel(configCreate) ??
viewModelsConfig.factory(configCreate);
instance.willMount();
viewModels?.markToBeAttached(instance);
return instance;
}
});
useIsomorphicLayoutEffect(() => {
if (viewModels) {
viewModels.attach(instance);
return () => {
viewModels.detach(instance.id);
};
}
else {
instance.mount();
return () => {
instance.willUnmount();
instance.unmount();
};
}
}, [instance]);
instance.setPayload(payload ?? {});
return instance;
};
const useCreateViewModelSimple = (VM, payload) => {
const viewModels = useContext(ViewModelsContext);
const instance = useValue(() => {
const instance = new VM();
viewModels?.markToBeAttached(instance);
return instance;
});
if ('setPayload' in instance) {
useLayoutEffect(() => {
instance.setPayload(payload);
}, [payload]);
}
useIsomorphicLayoutEffect(() => {
if (viewModels) {
viewModels.attach(instance);
return () => {
viewModels.detach(instance.id);
};
}
else {
instance.mount?.();
return () => {
instance.unmount?.();
};
}
}, [instance]);
return instance;
};