UNPKG

mobx-view-model

Version:
122 lines (121 loc) 4.16 kB
/* eslint-disable react-hooks/rules-of-hooks */ import { useContext, useLayoutEffect, useRef, useState } 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 { generateVMId } from '../utils/create-vm-id-generator.js'; const useCreateViewModelSimple = (VM, payload) => { const viewModels = useContext(ViewModelsContext); const lastInstance = useRef(null); const [instance] = useState(() => { if (lastInstance.current) { return lastInstance.current; } const instance = new VM(); viewModels?.markToBeAttached(instance); if (viewModels && instance.linkStore) { instance.linkStore(viewModels); } return instance; }); if ('setPayload' in instance) { useLayoutEffect(() => { instance.setPayload(payload); }, [payload]); } useIsomorphicLayoutEffect(() => { if (viewModels) { viewModels.attach(instance); return () => { viewModels.detach(instance.id); lastInstance.current = null; }; } else { instance.mount?.(); return () => { instance.unmount?.(); lastInstance.current = null; }; } }, []); return instance; }; /** * Creates new instance of ViewModel * * [**Documentation**](https://js2me.github.io/mobx-view-model/react/api/use-create-view-model.html) */ export function useCreateViewModel(VM, ...args) { const [payload, config] = args; if (!('willMount' in VM.prototype) && !('payloadChanged' in VM.prototype) && !('willUnmount' in VM.prototype)) { // scenario for ViewModelSimple return useCreateViewModelSimple(VM, payload); } const idRef = useRef(''); const viewModels = useContext(ViewModelsContext); const parentViewModel = useContext(ActiveViewModelContext) || null; const ctx = config?.ctx ?? {}; if (!idRef.current) { idRef.current = viewModels?.generateViewModelId({ ...config, ctx, VM, parentViewModelId: parentViewModel?.id, }) ?? config?.id ?? generateVMId(ctx); } const id = idRef.current; const instanceFromStore = viewModels ? viewModels.get(id) : null; const instanceRef = useRef(null); if (!instanceRef.current) { if (instanceFromStore) { instanceRef.current = 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); instanceRef.current = instance; instance.willMount(); viewModels?.markToBeAttached(instance); } } const instance = instanceRef.current; useIsomorphicLayoutEffect(() => { if (viewModels) { viewModels.attach(instance); return () => { viewModels.detach(instance.id); instanceRef.current = null; }; } else { instance.mount(); return () => { instance.willUnmount(); instance.unmount(); instanceRef.current = null; }; } }, []); instance.setPayload(payload ?? {}); return instance; }