Skip to content

Commit

Permalink
feat: use Action instead of extraData + value
Browse files Browse the repository at this point in the history
  • Loading branch information
everbrez committed Jan 30, 2024
1 parent 43d96b8 commit 88bf4a2
Show file tree
Hide file tree
Showing 23 changed files with 280 additions and 193 deletions.
8 changes: 5 additions & 3 deletions packages/core/demos/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { start, tracker, type TrackRecord } from '../src';
import { ExtraInfo } from '../src/ModelState/ExtraInfo';
import { Action } from '../src/ModelState';
import { SimpleDemoApp } from './simple-demo';
import { TodoListDemoApp } from './todo-list-demo';

Expand All @@ -12,14 +12,16 @@ function main() {
const appInstance = start(SimpleDemoApp);

console.log(appInstance.output?.result.current);
appInstance.output?.event.next(2, new ExtraInfo('manual add 2'));
appInstance.output?.event.next(new Action({ payload: 2, path: 'manual add 2' }));
console.log('result', appInstance.output?.result.current);

start(TodoListDemoApp);

setTimeout(() => {
console.log('====== RECORD ======');
console.log(JSON.stringify(logs, undefined, 2));
// TODO: MState record
// console.log(JSON.stringify(logs, undefined, 2));
console.log(logs);
console.log('====== RECORD END ======');
}, 10000);
}
Expand Down
8 changes: 4 additions & 4 deletions packages/core/demos/simple-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ export function SimpleDemoApp(input: any, context: ModelBlockContextType) {
event.pipe((item) => {
const value = new ModelState<number>(0);

item.subscribe((val, extraInfo) => {
value.update(val, extraInfo);
item.subscribe((action) => {
value.next(action);
});

return value;
}),
constValue(1)
).subscribe((res, extraInfo) => {
state2.update(res, extraInfo);
).subscribe((action) => {
state2.next(action);
});

return {
Expand Down
22 changes: 16 additions & 6 deletions packages/core/demos/sub-demo.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { ModelState, ModelEvent, type ModelBlockContextType } from '../src';
import { ExtraInfo } from '../src/ModelState/ExtraInfo';
import { Action } from '../src/ModelState';

function other1(input: any, context: ModelBlockContextType) {
const { onLifecycle } = context;
const count = new ModelState(0);
const event = new ModelEvent();
const event = new ModelEvent<number>();

onLifecycle('postInit', () => {
const subscription = count.subscribe((val, extraInfo) => {
event.next(val, extraInfo);
const subscription = count.subscribe((action) => {
event.next(action);
});

return subscription;
Expand Down Expand Up @@ -51,8 +51,18 @@ function Test(_input: any, context: ModelBlockContextType) {
const state2 = new ModelState(1);

onLifecycle('mount', () => {
state1.update((c) => c + 2, new ExtraInfo());
state2.update((c) => c * 5, new ExtraInfo());
state1.next(
new Action({
payload: (c) => c + 2,
path: 'mount'
})
);
state2.next(
new Action({
payload: (c) => c * 5,
path: 'mount'
})
);
});

return {
Expand Down
176 changes: 114 additions & 62 deletions packages/core/demos/todo-list-demo.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type ModelBlockContextType, ModelState, ModelEvent } from '../src';
import { proxyData, mountList } from '../src/operators';
import { ExtraInfo } from '../src/ModelState/ExtraInfo';
import { Action } from '../src/ModelState';

function TodoItem(
input: { index: ModelState<number>; data: ModelState<any[]>; key: string },
Expand All @@ -12,34 +12,49 @@ function TodoItem(
// delete
// change title
// check/uncheck
const deleteEvent = new ModelEvent();
const titleChangeEvent = new ModelEvent();
const deleteEvent = new ModelEvent<undefined>();
const titleChangeEvent = new ModelEvent<string>();
const checkEvent = new ModelEvent<boolean>();

deleteEvent.subscribe((_val, extraInfo) => {
data.update((data) => {
const dataWillUpdate = [...data];
dataWillUpdate.splice(index.current, 1);
return dataWillUpdate;
}, extraInfo);
deleteEvent.subscribe((action) => {
data.next(
action.concat({
payload: (data: any[]) => {
const dataWillUpdate = [...data];
dataWillUpdate.splice(index.current, 1);
return dataWillUpdate;
},
path: 'deleteEvent'
})
);
});

titleChangeEvent.subscribe((val, extraInfo) => {
data.update((data) => {
const dataWillUpdate = [...data];
const item = data[index.current];
item.title = val;
return dataWillUpdate;
}, extraInfo);
titleChangeEvent.subscribe((action) => {
data.next(
action.concat({
payload: (data: any[]) => {
const dataWillUpdate = [...data];
const item = data[index.current];
item.title = action.payload;
return dataWillUpdate;
},
path: 'titleChangeEvent'
})
);
});

checkEvent.subscribe((val, extraInfo) => {
data.update((data) => {
const dataWillUpdate = [...data];
const item = data[index.current];
item.checked = Boolean(val);
return dataWillUpdate;
}, extraInfo);
checkEvent.subscribe((action) => {
data.next(
action.concat({
payload: (data: any[]) => {
const dataWillUpdate = [...data];
const item = data[index.current];
item.checked = Boolean(action.payload);
return dataWillUpdate;
},
path: 'checkEvent'
})
);
});

onLifecycle('mount', () => {
Expand Down Expand Up @@ -72,28 +87,38 @@ function TodoListContainer(
// clear
const addItemEvent = new ModelEvent<{ key: string; title: string }>();
const checkAllEvent = new ModelEvent<boolean>();
const clearAllEvent = new ModelEvent();

addItemEvent.subscribe((val, extraInfo) => {
listData.update((list) => {
return list.concat({
...val,
checked: false
});
}, extraInfo);
const clearAllEvent = new ModelEvent<boolean>();

addItemEvent.subscribe((action) => {
listData.next(
action.concat({
payload: (list: any[]) => {
return list.concat({
...action.payload,
checked: false
});
},
path: 'addItemEvent'
})
);
});

checkAllEvent.subscribe((val, extraInfo) => {
listData.update((list) => {
return list.map((item) => ({
...item,
checked: Boolean(val)
}));
}, extraInfo);
checkAllEvent.subscribe((action) => {
listData.next(
action.concat({
payload: (list: any[]) => {
return list.map((item) => ({
...item,
checked: Boolean(action.payload)
}));
},
path: 'checkAllEvent'
})
);
});

clearAllEvent.subscribe((_val, extraInfo) => {
listData.update([], extraInfo);
clearAllEvent.subscribe((action) => {
listData.next(action.concat({ payload: [], path: 'clearAllEvent' }));
});

return {
Expand All @@ -109,10 +134,20 @@ export function TodoListDemoApp(_input: any, context: ModelBlockContextType) {
const data = new ModelState({ list: [{ key: 1 }] });
const listData = proxyData(data, 'list');

listData.update((list) => [...(list || []), { key: 777 }], new ExtraInfo('update list'));
listData.next(
new Action({
payload: (list) => [...(list || []), { key: 777 }],
path: 'update list'
})
);

setTimeout(() => {
listData.update((list) => [{ key: 777 }, { key: 99 }], new ExtraInfo('update list'));
listData.next(
new Action({
payload: (list) => [{ key: 777 }, { key: 99 }],
path: 'update list'
})
);
}, 1000);

console.log('listData', listData.current);
Expand All @@ -127,41 +162,58 @@ export function TodoListDemoApp(_input: any, context: ModelBlockContextType) {
setTimeout(() => {
// 增加一个
todoListContainerInstance.output?.addItemEvent.next(
{ key: '23333', title: 'new item' },
new ExtraInfo('add manually')
new Action({
payload: { key: '23333', title: 'new item' },
path: 'add manually'
})
);
console.log('listData addItemEvent', listData.current);
todoListContainerInstance.output?.checkAllEvent.next(
true,
new ExtraInfo('listData checkAllEvent true')
new Action({
payload: true,
path: 'listData checkAllEvent true'
})
);
console.log('listData checkAllEvent true', listData.current);
todoListContainerInstance.output?.checkAllEvent.next(
false,
new ExtraInfo('listData checkAllEvent false')
new Action({
payload: false,
path: 'listData checkAllEvent false'
})
);
console.log('listData checkAllEvent false', listData.current);

// change title
todoListContainerInstance.output?.instanceList?.current
?.at(-1)
?.instance.output?.titleChangeEvent.next(
'change - title',
new ExtraInfo('listData titleChangeEvent')
);
todoListContainerInstance.output?.instanceList?.current?.at(-1)?.instance.output?.titleChangeEvent.next(
new Action({
payload: 'change - title',
path: 'listData titleChangeEvent'
})
);
console.log('listData titleChangeEvent', listData.current);

todoListContainerInstance.output?.instanceList?.current
?.at(-1)
?.instance.output?.checkEvent.next(true, new ExtraInfo('listData checkEvent true'));
todoListContainerInstance.output?.instanceList?.current?.at(-1)?.instance.output?.checkEvent.next(
new Action({
payload: true,
path: 'listData checkEvent true'
})
);
console.log('listData checkEvent true', listData.current);

todoListContainerInstance.output?.instanceList?.current
?.at(-2)
?.instance.output?.deleteEvent.next(undefined, new ExtraInfo('listData deleteEvent'));
todoListContainerInstance.output?.instanceList?.current?.at(-2)?.instance.output?.deleteEvent.next(
new Action({
payload: undefined,
path: 'listData deleteEvent'
})
);
console.log('listData deleteEvent', listData.current);

todoListContainerInstance.output?.clearAllEvent.next(false, new ExtraInfo('listData clearAllEvent'));
todoListContainerInstance.output?.clearAllEvent.next(
new Action({
payload: false,
path: 'listData clearAllEvent'
})
);
console.log('listData clearAllEvent', listData.current);
}, 3000);
});
Expand Down
14 changes: 3 additions & 11 deletions packages/core/src/ModelState/Action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,12 @@ import { Entity } from '../Entity';

export type IUpdateAction<T> = (source: T) => T;

function isAction<T, ExtraData extends Record<string, any>>(data: any): data is Action<T, ExtraData> {
return typeof data === 'object';
}

function isUpdateAction(data: any): data is IUpdateAction<any> {
return !isAction(data);
}

type IActionObjectParam<T extends Action = Action> = Required<Pick<T, 'action' | 'path'>> &
type IActionObjectParam<T extends Action = Action> = Required<Pick<T, 'payload' | 'path'>> &
Partial<Pick<T, 'uid' | 'from' | 'extra'>>;

export class Action<T = any, ExtraData extends Record<string, any> = Record<string, any>> extends Entity {
/** UpdateAction */
action?: T | IUpdateAction<T>;
/** UpdateAction, value or function */
payload: T | IUpdateAction<T> | undefined;
/** value update hint */
path: string = '';
/** extra data */
Expand Down
20 changes: 0 additions & 20 deletions packages/core/src/ModelState/ExtraInfo.ts

This file was deleted.

6 changes: 3 additions & 3 deletions packages/core/src/ModelState/ModelEvent.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ExtraInfo } from './ExtraInfo';
import { Observable } from './Observable';
import { Action } from './Action';

export class ModelEvent<T> extends Observable<T> {
next(info: T, extraInfo: ExtraInfo) {
super.next(info, extraInfo || new ExtraInfo('[ModelEvent] fallback'));
next(action?: Action<T>) {
super.trigger(action || new Action<T>({ payload: undefined, path: 'event' }));
}
}
Loading

0 comments on commit 88bf4a2

Please sign in to comment.