Skip to content

Commit

Permalink
feat: add *MState
Browse files Browse the repository at this point in the history
  • Loading branch information
everbrez committed Feb 12, 2024
1 parent 7bb2ff9 commit 7f51769
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 53 deletions.
41 changes: 35 additions & 6 deletions packages/core/src/ModelBlock/ModelBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@ type SelfLifeCycleType =
| 'beforeUnmountSelf'
| 'unmountSelf';

const cleanUpLifecycleMap: Record<LifecycleEventType, LifecycleEventType | undefined> = {
beforeMount: 'beforeUnmount',
mount: 'unmount',
preInit: 'preUnmount',
postInit: 'postUnmount',
preMount: 'preUnmount',
postMount: 'postUnmount',
postUnmount: undefined,
preUnmount: undefined,
start: undefined,
stop: undefined,
beforeUnmount: undefined,
unmount: undefined
};

export type AtomLifecycleEventType = Exclude<LifecycleEventType, 'start' | 'stop' | 'preInit'>;

export interface ModelBlockContextType {
Expand All @@ -40,8 +55,8 @@ export interface ModelBlockContextType {
mount: <I extends InputOutputInterface, O extends InputOutputInterface>(
template: SetupFn<I, O>,
input?: I
) => ModelConstructor<I, O>;
unmount: (node: ModelConstructor) => void;
) => ModelBlock<I, O>;
unmount: (node: ModelBlock) => void;
}

export enum ModelBlockStatus {
Expand Down Expand Up @@ -131,10 +146,24 @@ export class ModelBlock<
lifecycleType: AtomLifecycleEventType,
callback: CallbackType
) {
this.eventEmitter.on(lifecycleType, callback);
let cleanupFn: CallbackType | undefined;
const cleanupLifecycle = cleanUpLifecycleMap[lifecycleType];

const callbackWrapper = () => {
cleanupFn = callback();
if (typeof cleanupFn === 'function' && cleanupLifecycle) {
this.eventEmitter.on(cleanupLifecycle, cleanupFn);
}
};

this.eventEmitter.on(lifecycleType, callbackWrapper);

return {
unsubscribe: () => {
this.eventEmitter.off(lifecycleType, callback);
this.eventEmitter.off(lifecycleType, callbackWrapper);
if (cleanupFn && cleanupLifecycle) {
this.eventEmitter.off(cleanupLifecycle, cleanupFn);
}
}
};
}
Expand All @@ -160,7 +189,7 @@ export class ModelBlock<
protected mountTemplate<I extends InputOutputInterface, O extends InputOutputInterface>(
template: SetupFn<I, O>,
input?: I
): ModelConstructor<I, O> {
): ModelBlock<I, O> {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
/** @ts-expect-error */
if (template === this.template) {
Expand Down Expand Up @@ -199,7 +228,7 @@ export class ModelBlock<
}
}

protected unmountChild(block: ModelConstructor) {
protected unmountChild(block: ModelBlock) {
if (block instanceof ModelBlock) {
this.relationHelper.removeChild(block);
block.unmount();
Expand Down
3 changes: 1 addition & 2 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ export {
export { ModelState, ModelEvent, Action, ModelEventProxy, ModelStateProxy } from './ModelState';
export { type Observable } from './ModelState/Observable';
export { tracker, type TrackRecord } from './Tracker';
// not ready
// export { ConditionMState, LazyMState, ListMState } from './models';
export { ConditionMState, ListMState } from './models';
45 changes: 39 additions & 6 deletions packages/core/src/models/ConditionMState.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
import { ModelBlockContextType, SetupFn } from '../ModelBlock';
import { ModelBlock, ModelBlockContextType, SetupFn } from '../ModelBlock';
import { Action, ModelState } from '../ModelState';
import { Observable } from '../ModelState/Observable';

export function ConditionMState<T extends { state: Observable<any>; setup: () => void }>(
input: T,
context: ModelBlockContextType
) {
return {};
export function ConditionMState<
T extends {
state: Observable<boolean>;
templateState: ModelState<SetupFn<{ index: ModelState<number>; data: T['state']; key: string }, any>>;
}
>(input: T, context: ModelBlockContextType) {
const { state, templateState, ...others } = input;
const { mount, onLifecycle } = context;

const modelState = new ModelState<ModelBlock<any, any> | undefined>(undefined);

onLifecycle('postInit', () => {
const subscription = state.subscribe((action) => {
if (modelState.current) {
modelState.current.unmount();
}

if (action.payload) {
modelState.next(
new Action({
// TODO: fix ts
payload: mount(templateState.current, { ...others } as any) as any,
path: 'ConditionMState mount'
})
);
}
});

return () => {
subscription.unsubscribe();
};
});

return {
// remain state structure, use custom/group operator to do the rest logic
modelState
};
}
9 changes: 0 additions & 9 deletions packages/core/src/models/LazyMState.ts

This file was deleted.

82 changes: 53 additions & 29 deletions packages/core/src/models/ListMState.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,55 @@
import { ModelBlockContextType, SetupFn, InputOutputInterface } from '../ModelBlock';
import { ModelState } from '../ModelState';
import { ModelBlockContextType, SetupFn, ModelBlock } from '../ModelBlock';
import { Action, ModelState } from '../ModelState';
import { get } from 'lodash';

export function ListMState<Data extends ModelState<any[]>, Output extends InputOutputInterface>(
input: {
data: Data;
export function ListMState<
T extends {
listState: ModelState<Record<any, any>[]>;
templateState: ModelState<SetupFn<{ index: ModelState<number>; data: T['listState']; key: string }, any>>;
key: string;
template: ModelState<SetupFn<{ index: ModelState<number>; data: Data; key: string }, Output>>;
},
context: ModelBlockContextType
) {
const { data, key, template } = input;
const { mount, unmount } = context;
}
>(input: T, context: ModelBlockContextType) {
const { listState, key, templateState } = input;
const { mount, unmount, onLifecycle } = context;

const instanceList = new ModelState(
data.current.map((value, index) => {
const indexState = new ModelState(index);
const keyValue = get(value, key);
const modelList = new ModelState<
{
key: any;
index: ModelState<number>;
instance: ModelBlock<
{
index: ModelState<number>;
data: T['listState'];
key: string;
},
any
>;
}[]
>([]);

return {
key: keyValue,
index: indexState,
instance: mount(template.current, { index: indexState, data, key: keyValue })
};
}) || []
);
onLifecycle('postInit', () => {
modelList.next(
new Action({
payload:
listState.current.map((value, index) => {
const indexState = new ModelState(index);
const keyValue = get(value, key);

data.subscribe((action) => {
return {
key: keyValue,
index: indexState,
instance: mount(templateState.current, { index: indexState, data: listState, key: keyValue })
};
}) || [],
path: 'instanceList init'
})
);
});

listState.subscribe((action) => {
// console.log('change::', data.current, instanceList);
const nextList = data.current.map((item, index) => ({ key: get(item, key), index }));
const currentList = instanceList.current;
const nextList = listState.current.map((item, index) => ({ key: get(item, key), index }));
const currentList = modelList.current;
// reconciliation
const nextKeyMap = new Map(nextList.map((item) => [item.key, item]));
const currentKeyMap = new Map(currentList.map((item) => [item.key, item]));
Expand All @@ -55,7 +75,11 @@ export function ListMState<Data extends ModelState<any[]>, Output extends InputO
const itemWillMount = {
index: indexState,
key: currentNextItem.key,
instance: mount(template.current, { index: indexState, data, key: currentNextItem.key })
instance: mount(templateState.current, {
index: indexState,
data: listState,
key: currentNextItem.key
})
};
nextInstanceList.push(itemWillMount);
console.log('mount ==> ', itemWillMount.key);
Expand All @@ -70,11 +94,11 @@ export function ListMState<Data extends ModelState<any[]>, Output extends InputO
unmount(node.instance);
});

instanceList.next(action.concat({ payload: nextInstanceList, path: 'ListMState' }));
modelList.next(action.concat({ payload: nextInstanceList, path: 'ListMState' }));
});

return {
data,
instanceList
listState,
modelList
};
}
1 change: 0 additions & 1 deletion packages/core/src/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export { ConditionMState } from './ConditionMState';
export { ListMState } from './ListMState';
export { LazyMState } from './LazyMState';

0 comments on commit 7f51769

Please sign in to comment.