From b2c1760c6eb771ad141be87d00e1ca47dbb1c921 Mon Sep 17 00:00:00 2001 From: Xc Date: Thu, 19 Dec 2024 14:53:35 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BA=86=E4=B8=80=E4=BA=9Bmo?= =?UTF-8?q?di=E7=9A=84=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- es/cacheStore/CacheStore.d.ts | 4 +- .../relation/path/upsert/web.pc.d.ts | 1 + es/components/relation/path/upsert/web.pc.js | 2 +- es/features/cache.js | 6 + es/features/runningTree.d.ts | 20 ++- es/features/runningTree.js | 108 ++++++++------- es/page.common.js | 8 +- es/page.mp.js | 4 +- es/page.react.js | 4 +- es/types/Page.d.ts | 1 - lib/cacheStore/CacheStore.d.ts | 4 +- lib/features/runningTree.d.ts | 20 ++- lib/features/runningTree.js | 108 ++++++++------- lib/page.common.js | 8 +- lib/page.mp.js | 4 +- lib/page.native.d.ts | 3 +- lib/page.react.d.ts | 21 ++- lib/page.react.js | 4 +- lib/page.web.d.ts | 3 +- lib/page.web.js | 1 - lib/platforms/native/features/index.d.ts | 4 +- lib/platforms/native/router/withRouter.d.ts | 3 +- lib/platforms/web/Loading.d.ts | 3 +- lib/platforms/web/PullToRefresh.js | 1 - lib/platforms/web/features/index.d.ts | 2 +- .../web/initialize/AppContainer.d.ts | 2 +- lib/platforms/web/initialize/AppError.d.ts | 2 +- lib/platforms/web/initialize/AppError.js | 28 +++- lib/platforms/web/initialize/AppRouter.d.ts | 2 +- lib/platforms/web/initialize/index.js | 2 - lib/platforms/web/responsive/context.d.ts | 5 +- lib/platforms/web/router/withRouter.d.ts | 3 +- lib/types/Page.d.ts | 1 - src/cacheStore/CacheStore.ts | 4 +- .../relation/path/upsert/web.pc.tsx | 3 +- src/features/runningTree.ts | 131 ++++++++++-------- src/page.common.ts | 8 +- src/page.mp.ts | 4 +- src/page.react.tsx | 4 +- src/types/Page.ts | 2 +- 40 files changed, 319 insertions(+), 229 deletions(-) diff --git a/es/cacheStore/CacheStore.d.ts b/es/cacheStore/CacheStore.d.ts index 3097f6f6..8779427b 100644 --- a/es/cacheStore/CacheStore.d.ts +++ b/es/cacheStore/CacheStore.d.ts @@ -2,7 +2,7 @@ import { AggregationResult, EntityDict, OperationResult, OpRecord, SelectOption import { StorageSchema } from "oak-domain/lib/types/Storage"; import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain'; import { Checker, CheckerType, TxnOption } from 'oak-domain/lib/types'; -import { TreeStore, TreeStoreOperateOption } from 'oak-memory-tree-store'; +import { TreeStore, TreeStoreOperateOption, TreeStoreSelectOption } from 'oak-memory-tree-store'; import { SyncContext, SyncRowStore } from 'oak-domain/lib/store/SyncRowStore'; interface CachStoreOperation extends TreeStoreOperateOption { checkerTypes?: CheckerType[]; @@ -19,7 +19,7 @@ export declare class CacheStore extends data?: ED[T]['Operation']['data']; filter?: ED[T]['Operation']['filter']; }, context: SyncContext, checkerTypes?: CheckerType[]): void; - select>(entity: T, selection: ED[T]['Selection'], context: Cxt, option: OP): Partial[]; + select>(entity: T, selection: ED[T]['Selection'], context: Cxt, option: OP): Partial[]; registerChecker(checker: Checker>): void; count(entity: T, selection: Pick, context: SyncContext, option: OP): number; begin(option?: TxnOption): string; diff --git a/es/components/relation/path/upsert/web.pc.d.ts b/es/components/relation/path/upsert/web.pc.d.ts index 1d8fa152..8cb6faf7 100644 --- a/es/components/relation/path/upsert/web.pc.d.ts +++ b/es/components/relation/path/upsert/web.pc.d.ts @@ -16,6 +16,7 @@ export default function render(props: WebComponentProps void; selectPath: (value: string) => void; diff --git a/es/components/relation/path/upsert/web.pc.js b/es/components/relation/path/upsert/web.pc.js index 6bdc0055..44201497 100644 --- a/es/components/relation/path/upsert/web.pc.js +++ b/es/components/relation/path/upsert/web.pc.js @@ -54,7 +54,7 @@ export default function render(props) { } - diff --git a/es/features/cache.js b/es/features/cache.js index a0a8bbdd..b1d64b45 100644 --- a/es/features/cache.js +++ b/es/features/cache.js @@ -440,12 +440,18 @@ export class Cache extends Feature { const result = this.cacheStore.select(entity, selection, this.context, { dontCollect: true, includedDeleted: true, + warnWhenAttributeMiss: !this.refreshing && process.env.NODE_ENV === 'development', }); rollback && rollback(); return result; } catch (err) { rollback && rollback(); + if (err instanceof OakRowUnexistedException) { + // 现在只有外键缺失会抛出RowUnexisted异常,前台在modi中连接了其它表的外键时会出现 + this.fetchRows(err.getRows()); + return []; + } throw err; } } diff --git a/es/features/runningTree.d.ts b/es/features/runningTree.d.ts index 1e187f16..4bbbc309 100644 --- a/es/features/runningTree.d.ts +++ b/es/features/runningTree.d.ts @@ -133,7 +133,7 @@ declare class ListNode, refresh?: boolean): void; removeNamedSorter(sorter: NamedSorterItem, refresh?: boolean): void; removeNamedSorterByName(name: string, refresh: boolean): void; - getFreshValue(inModi?: boolean): Array>; + getFreshValue(inModiNextBranch?: boolean): Array>; private addItemInner; addItem(lsn: number, item: Omit & { id?: string; @@ -286,13 +286,10 @@ export declare class RunningTree extends private root; constructor(cache: Cache, schema: StorageSchema); createNode(options: CreateNodeOptions, isPage: boolean): ListNode | SingleNode | VirtualNode; - private checkSingleNodeIsModiNode; - checkIsModiNode(path: string): boolean; + checkIsInModiNextBranch(path: string): boolean; private findNode; destroyNode(path: string, isPage: boolean): void; begin(): () => void; - redoBranchOperations(path: string): void; - redoBranchModis(path: string): void; getFreshValue(path: string): Partial | Partial[] | undefined; isDirty(path: string): boolean; addItem(path: string, data: Omit & { @@ -349,6 +346,19 @@ export declare class RunningTree extends entity: keyof ED; operation: ED[keyof ED]["Operation"]; }[] | undefined; + private cachedOperations; + private cachedModis; + /** + * 这个函数在reRender时可能会反复调用,composeOperations很消耗性能,在这里要做个缓存 + * @param path + */ + redoBranchOperations(path: string): void; + /** + * 这个函数在reRender时可能会反复调用,getModiOperations很消耗性能,在这里要做个缓存 + * @param path + */ + redoBranchModis(path: string): void; + tryExecute(path: string, action?: string): void; execute(path: string, action?: ED[T]['Action'], opers?: Array<{ entity: keyof ED; operation: ED[keyof ED]['Operation']; diff --git a/es/features/runningTree.js b/es/features/runningTree.js index 8253919a..7319b319 100644 --- a/es/features/runningTree.js +++ b/es/features/runningTree.js @@ -703,7 +703,7 @@ class ListNode extends EntityNode { this.publish(); } } - getFreshValue(inModi) { + getFreshValue(inModiNextBranch) { /** * 现在简化情况,只取sr中有id的数据,以及addItem中的create数据 * 但是对于modi查询,需要查询“热更新”部分的数据(因为这部分数据不会被sync到内存中,逻辑不严密,后面再说) @@ -716,7 +716,7 @@ class ListNode extends EntityNode { /** * 在非modi状态下,所取数据是在ids2中满足filter的部分(自身对象和其它对象的更新可能会影响这些行不再满足条件) */ - const filter2 = inModi ? filter : (ids2.length > 0 ? combineFilters(this.entity, this.cache.getSchema(), [filter, { + const filter2 = inModiNextBranch ? filter : (ids2.length > 0 ? combineFilters(this.entity, this.cache.getSchema(), [filter, { id: { $in: ids2, } @@ -724,7 +724,7 @@ class ListNode extends EntityNode { if (filter2 && data) { const result = this.cache.get(this.entity, { data, - filter: inModi ? filter : filter2, + filter: inModiNextBranch ? filter : filter2, sorter, }, this.sr); return result; @@ -1886,40 +1886,30 @@ export class RunningTree extends Feature { } return node; } - checkSingleNodeIsModiNode(node) { - const id = node.getId(); - if (id) { - const modies = this.cache.get('modi', { - data: { - id: 1, - }, - filter: { - targetEntity: node.getEntity(), - action: 'create', - data: { - id, - }, - iState: 'active', - } - }); - return modies.length > 0; - } - return false; - } - checkIsModiNode(path) { + // 判断当前结点是否在:next的路径上(且有前项结点,两者同时满足就不用refresh了) + checkIsInModiNextBranch(path) { if (!path.includes(MODI_NEXT_PATH_SUFFIX)) { return false; } - const node = this.findNode(path); - if (node instanceof SingleNode) { - return this.checkSingleNodeIsModiNode(node); + const paths = path.split('.'); + if (paths[0].includes(MODI_NEXT_PATH_SUFFIX)) { + // 根结点就是:next,这时候还是要取的 + return false; } - else { - assert(node instanceof ListNode); - const parent = node.getParent(); - assert(parent instanceof SingleNode); - return this.checkSingleNodeIsModiNode(parent); + let iter = 1; + while (iter < paths.length) { + if (paths[iter].includes(MODI_NEXT_PATH_SUFFIX)) { + const path2 = paths.slice(0, iter) + paths[iter].replace(MODI_NEXT_PATH_SUFFIX, ''); + const node = this.findNode(path2); + if (node) { + return true; + } + return false; + } + iter++; } + assert(false); + return false; } findNode(path) { if (this.root[path]) { @@ -1967,29 +1957,11 @@ export class RunningTree extends Feature { begin() { return this.cache.begin(); } - redoBranchOperations(path) { - const paths = path.split('.'); - const root = paths.shift(); - const rootNode = this.root[root]; - const opers = rootNode.composeOperations(paths); - if (opers) { - this.cache.redoOperation(opers); - } - } - redoBranchModis(path) { - const { root } = analyzePath(path); - const rootNode = this.root[root]; - const includeModi = path.includes(MODI_NEXT_PATH_SUFFIX); - if (includeModi) { - const modiOperations = rootNode.getModiOperations(); - modiOperations && this.cache.redoOperation(modiOperations); - } - } getFreshValue(path) { const node = this.findNode(path); if (node instanceof ListNode) { - const includeModi = path.includes(MODI_NEXT_PATH_SUFFIX); - return node.getFreshValue(includeModi); + const inModiNextBranch = path.includes(MODI_NEXT_PATH_SUFFIX) && !path.endsWith(MODI_NEXT_PATH_SUFFIX); + return node.getFreshValue(inModiNextBranch); } assert(node instanceof SingleNode); return node.getFreshValue(); @@ -2214,13 +2186,43 @@ export class RunningTree extends Feature { const operations = node?.composeOperations(); return operations; } + cachedOperations = {}; + cachedModis = {}; + /** + * 这个函数在reRender时可能会反复调用,composeOperations很消耗性能,在这里要做个缓存 + * @param path + */ + redoBranchOperations(path) { + const paths = path.split('.'); + const root = paths.shift(); + const rootNode = this.root[root]; + const opers = rootNode.composeOperations(paths); + if (opers) { + this.cache.redoOperation(opers); + } + } + /** + * 这个函数在reRender时可能会反复调用,getModiOperations很消耗性能,在这里要做个缓存 + * @param path + */ + redoBranchModis(path) { + const { root } = analyzePath(path); + const rootNode = this.root[root]; + const includeModi = path.includes(MODI_NEXT_PATH_SUFFIX); + if (includeModi) { + const modiOperations = rootNode.getModiOperations(); + modiOperations && this.cache.redoOperation(modiOperations); + } + } + tryExecute(path, action) { + } async execute(path, action, opers) { const node = this.findNode(path); // assert(node.isDirty()); node.setExecuting(true); let pollute = false; try { - let operations = node.composeOperations() || []; + let operations = this.getOperations(path) || []; if (opers) { operations.push(...opers); } diff --git a/es/page.common.js b/es/page.common.js index 3b979577..b4284db9 100644 --- a/es/page.common.js +++ b/es/page.common.js @@ -422,7 +422,8 @@ export function reRender(option, extra) { const oakLoadingMore = this.features.runningTree.isLoadingMore(this.state.oakFullpath); const oakLoading = !oakLoadingMore && this.features.runningTree.isLoading(this.state.oakFullpath); const oakExecuting = this.features.runningTree.isExecuting(this.state.oakFullpath); - const oakExecutable = !oakExecuting && this.tryExecute(); + // 这个很耗时,让用户去相应要execute的页面上调用 + // const oakExecutable = !oakExecuting && this.tryExecute(); // 现在取数据需要把runningTree上的更新应用了再取,判定actions也一样 let rollback = this.features.runningTree.begin(); try { @@ -489,7 +490,6 @@ export function reRender(option, extra) { } ; Object.assign(data, { - oakExecutable, oakDirty, oakLoading, oakLoadingMore, @@ -523,11 +523,11 @@ export function reRender(option, extra) { */ const oakDirty = this.features.runningTree.isDirty(this.state.oakFullpath); const oakExecuting = this.features.runningTree.isExecuting(this.state.oakFullpath); - const oakExecutable = !oakExecuting && this.tryExecute(); + // const oakExecutable = !oakExecuting && this.tryExecute(); const oakLoading = this.features.runningTree.isLoading(this.state.oakFullpath); Object.assign(data, { oakDirty, - oakExecutable, + // oakExecutable, oakExecuting, oakLoading, }); diff --git a/es/page.mp.js b/es/page.mp.js index e83ee5c5..5f7b9f7c 100644 --- a/es/page.mp.js +++ b/es/page.mp.js @@ -486,7 +486,7 @@ const oakBehavior = Behavior({ this.oakOption.lifetimes?.ready.call(this); const { oakFullpath } = this.state; if (oakFullpath && !this.oakOption.stale && - !this.features.runningTree.checkIsModiNode(oakFullpath) && + !this.features.runningTree.checkIsInModiNextBranch(oakFullpath) && !this.features.runningTree.isListDescandent(oakFullpath)) { this.refresh(); } @@ -791,7 +791,7 @@ export function createComponent(option, features) { } const { oakFullpath } = this.state; if (oakFullpath && !option.stale && - !features.runningTree.checkIsModiNode(oakFullpath) && + !features.runningTree.checkIsInModiNextBranch(oakFullpath) && !features.runningTree.isListDescandent(oakFullpath)) { try { await this.refresh(); diff --git a/es/page.react.js b/es/page.react.js index 808c3189..b0dbcb2b 100644 --- a/es/page.react.js +++ b/es/page.react.js @@ -647,7 +647,7 @@ export function createComponent(option, features) { try { const { oakFullpath } = this.state; if (oakFullpath && !option.stale && - !features.runningTree.checkIsModiNode(oakFullpath) && + !features.runningTree.checkIsInModiNextBranch(oakFullpath) && !features.runningTree.isListDescandent(oakFullpath)) { await this.refresh(); } @@ -707,7 +707,7 @@ export function createComponent(option, features) { } const { oakFullpath } = this.state; if (oakFullpath && !option.stale && - !features.runningTree.checkIsModiNode(oakFullpath) && + !features.runningTree.checkIsInModiNextBranch(oakFullpath) && !features.runningTree.isListDescandent(oakFullpath)) { this.refresh(); } diff --git a/es/types/Page.d.ts b/es/types/Page.d.ts index 6ad77f43..7cdaba98 100644 --- a/es/types/Page.d.ts +++ b/es/types/Page.d.ts @@ -325,7 +325,6 @@ export type OakComponentOnlyMethods = { setOakActions: () => void; }; export type OakComponentData = { - oakExecutable: boolean | Error; oakExecuting: boolean; oakFocused: { attr: string; diff --git a/lib/cacheStore/CacheStore.d.ts b/lib/cacheStore/CacheStore.d.ts index 3097f6f6..8779427b 100644 --- a/lib/cacheStore/CacheStore.d.ts +++ b/lib/cacheStore/CacheStore.d.ts @@ -2,7 +2,7 @@ import { AggregationResult, EntityDict, OperationResult, OpRecord, SelectOption import { StorageSchema } from "oak-domain/lib/types/Storage"; import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain'; import { Checker, CheckerType, TxnOption } from 'oak-domain/lib/types'; -import { TreeStore, TreeStoreOperateOption } from 'oak-memory-tree-store'; +import { TreeStore, TreeStoreOperateOption, TreeStoreSelectOption } from 'oak-memory-tree-store'; import { SyncContext, SyncRowStore } from 'oak-domain/lib/store/SyncRowStore'; interface CachStoreOperation extends TreeStoreOperateOption { checkerTypes?: CheckerType[]; @@ -19,7 +19,7 @@ export declare class CacheStore extends data?: ED[T]['Operation']['data']; filter?: ED[T]['Operation']['filter']; }, context: SyncContext, checkerTypes?: CheckerType[]): void; - select>(entity: T, selection: ED[T]['Selection'], context: Cxt, option: OP): Partial[]; + select>(entity: T, selection: ED[T]['Selection'], context: Cxt, option: OP): Partial[]; registerChecker(checker: Checker>): void; count(entity: T, selection: Pick, context: SyncContext, option: OP): number; begin(option?: TxnOption): string; diff --git a/lib/features/runningTree.d.ts b/lib/features/runningTree.d.ts index 1e187f16..4bbbc309 100644 --- a/lib/features/runningTree.d.ts +++ b/lib/features/runningTree.d.ts @@ -133,7 +133,7 @@ declare class ListNode, refresh?: boolean): void; removeNamedSorter(sorter: NamedSorterItem, refresh?: boolean): void; removeNamedSorterByName(name: string, refresh: boolean): void; - getFreshValue(inModi?: boolean): Array>; + getFreshValue(inModiNextBranch?: boolean): Array>; private addItemInner; addItem(lsn: number, item: Omit & { id?: string; @@ -286,13 +286,10 @@ export declare class RunningTree extends private root; constructor(cache: Cache, schema: StorageSchema); createNode(options: CreateNodeOptions, isPage: boolean): ListNode | SingleNode | VirtualNode; - private checkSingleNodeIsModiNode; - checkIsModiNode(path: string): boolean; + checkIsInModiNextBranch(path: string): boolean; private findNode; destroyNode(path: string, isPage: boolean): void; begin(): () => void; - redoBranchOperations(path: string): void; - redoBranchModis(path: string): void; getFreshValue(path: string): Partial | Partial[] | undefined; isDirty(path: string): boolean; addItem(path: string, data: Omit & { @@ -349,6 +346,19 @@ export declare class RunningTree extends entity: keyof ED; operation: ED[keyof ED]["Operation"]; }[] | undefined; + private cachedOperations; + private cachedModis; + /** + * 这个函数在reRender时可能会反复调用,composeOperations很消耗性能,在这里要做个缓存 + * @param path + */ + redoBranchOperations(path: string): void; + /** + * 这个函数在reRender时可能会反复调用,getModiOperations很消耗性能,在这里要做个缓存 + * @param path + */ + redoBranchModis(path: string): void; + tryExecute(path: string, action?: string): void; execute(path: string, action?: ED[T]['Action'], opers?: Array<{ entity: keyof ED; operation: ED[keyof ED]['Operation']; diff --git a/lib/features/runningTree.js b/lib/features/runningTree.js index 8a91f529..c1e3b71d 100644 --- a/lib/features/runningTree.js +++ b/lib/features/runningTree.js @@ -706,7 +706,7 @@ class ListNode extends EntityNode { this.publish(); } } - getFreshValue(inModi) { + getFreshValue(inModiNextBranch) { /** * 现在简化情况,只取sr中有id的数据,以及addItem中的create数据 * 但是对于modi查询,需要查询“热更新”部分的数据(因为这部分数据不会被sync到内存中,逻辑不严密,后面再说) @@ -719,7 +719,7 @@ class ListNode extends EntityNode { /** * 在非modi状态下,所取数据是在ids2中满足filter的部分(自身对象和其它对象的更新可能会影响这些行不再满足条件) */ - const filter2 = inModi ? filter : (ids2.length > 0 ? (0, filter_1.combineFilters)(this.entity, this.cache.getSchema(), [filter, { + const filter2 = inModiNextBranch ? filter : (ids2.length > 0 ? (0, filter_1.combineFilters)(this.entity, this.cache.getSchema(), [filter, { id: { $in: ids2, } @@ -727,7 +727,7 @@ class ListNode extends EntityNode { if (filter2 && data) { const result = this.cache.get(this.entity, { data, - filter: inModi ? filter : filter2, + filter: inModiNextBranch ? filter : filter2, sorter, }, this.sr); return result; @@ -1889,40 +1889,30 @@ class RunningTree extends Feature_1.Feature { } return node; } - checkSingleNodeIsModiNode(node) { - const id = node.getId(); - if (id) { - const modies = this.cache.get('modi', { - data: { - id: 1, - }, - filter: { - targetEntity: node.getEntity(), - action: 'create', - data: { - id, - }, - iState: 'active', - } - }); - return modies.length > 0; - } - return false; - } - checkIsModiNode(path) { + // 判断当前结点是否在:next的路径上(且有前项结点,两者同时满足就不用refresh了) + checkIsInModiNextBranch(path) { if (!path.includes(exports.MODI_NEXT_PATH_SUFFIX)) { return false; } - const node = this.findNode(path); - if (node instanceof SingleNode) { - return this.checkSingleNodeIsModiNode(node); + const paths = path.split('.'); + if (paths[0].includes(exports.MODI_NEXT_PATH_SUFFIX)) { + // 根结点就是:next,这时候还是要取的 + return false; } - else { - (0, assert_1.assert)(node instanceof ListNode); - const parent = node.getParent(); - (0, assert_1.assert)(parent instanceof SingleNode); - return this.checkSingleNodeIsModiNode(parent); + let iter = 1; + while (iter < paths.length) { + if (paths[iter].includes(exports.MODI_NEXT_PATH_SUFFIX)) { + const path2 = paths.slice(0, iter) + paths[iter].replace(exports.MODI_NEXT_PATH_SUFFIX, ''); + const node = this.findNode(path2); + if (node) { + return true; + } + return false; + } + iter++; } + (0, assert_1.assert)(false); + return false; } findNode(path) { if (this.root[path]) { @@ -1970,29 +1960,11 @@ class RunningTree extends Feature_1.Feature { begin() { return this.cache.begin(); } - redoBranchOperations(path) { - const paths = path.split('.'); - const root = paths.shift(); - const rootNode = this.root[root]; - const opers = rootNode.composeOperations(paths); - if (opers) { - this.cache.redoOperation(opers); - } - } - redoBranchModis(path) { - const { root } = analyzePath(path); - const rootNode = this.root[root]; - const includeModi = path.includes(exports.MODI_NEXT_PATH_SUFFIX); - if (includeModi) { - const modiOperations = rootNode.getModiOperations(); - modiOperations && this.cache.redoOperation(modiOperations); - } - } getFreshValue(path) { const node = this.findNode(path); if (node instanceof ListNode) { - const includeModi = path.includes(exports.MODI_NEXT_PATH_SUFFIX); - return node.getFreshValue(includeModi); + const inModiNextBranch = path.includes(exports.MODI_NEXT_PATH_SUFFIX) && !path.endsWith(exports.MODI_NEXT_PATH_SUFFIX); + return node.getFreshValue(inModiNextBranch); } (0, assert_1.assert)(node instanceof SingleNode); return node.getFreshValue(); @@ -2217,13 +2189,43 @@ class RunningTree extends Feature_1.Feature { const operations = node?.composeOperations(); return operations; } + cachedOperations = {}; + cachedModis = {}; + /** + * 这个函数在reRender时可能会反复调用,composeOperations很消耗性能,在这里要做个缓存 + * @param path + */ + redoBranchOperations(path) { + const paths = path.split('.'); + const root = paths.shift(); + const rootNode = this.root[root]; + const opers = rootNode.composeOperations(paths); + if (opers) { + this.cache.redoOperation(opers); + } + } + /** + * 这个函数在reRender时可能会反复调用,getModiOperations很消耗性能,在这里要做个缓存 + * @param path + */ + redoBranchModis(path) { + const { root } = analyzePath(path); + const rootNode = this.root[root]; + const includeModi = path.includes(exports.MODI_NEXT_PATH_SUFFIX); + if (includeModi) { + const modiOperations = rootNode.getModiOperations(); + modiOperations && this.cache.redoOperation(modiOperations); + } + } + tryExecute(path, action) { + } async execute(path, action, opers) { const node = this.findNode(path); // assert(node.isDirty()); node.setExecuting(true); let pollute = false; try { - let operations = node.composeOperations() || []; + let operations = this.getOperations(path) || []; if (opers) { operations.push(...opers); } diff --git a/lib/page.common.js b/lib/page.common.js index 6cacb49f..65d6311b 100644 --- a/lib/page.common.js +++ b/lib/page.common.js @@ -426,7 +426,8 @@ function reRender(option, extra) { const oakLoadingMore = this.features.runningTree.isLoadingMore(this.state.oakFullpath); const oakLoading = !oakLoadingMore && this.features.runningTree.isLoading(this.state.oakFullpath); const oakExecuting = this.features.runningTree.isExecuting(this.state.oakFullpath); - const oakExecutable = !oakExecuting && this.tryExecute(); + // 这个很耗时,让用户去相应要execute的页面上调用 + // const oakExecutable = !oakExecuting && this.tryExecute(); // 现在取数据需要把runningTree上的更新应用了再取,判定actions也一样 let rollback = this.features.runningTree.begin(); try { @@ -493,7 +494,6 @@ function reRender(option, extra) { } ; Object.assign(data, { - oakExecutable, oakDirty, oakLoading, oakLoadingMore, @@ -527,11 +527,11 @@ function reRender(option, extra) { */ const oakDirty = this.features.runningTree.isDirty(this.state.oakFullpath); const oakExecuting = this.features.runningTree.isExecuting(this.state.oakFullpath); - const oakExecutable = !oakExecuting && this.tryExecute(); + // const oakExecutable = !oakExecuting && this.tryExecute(); const oakLoading = this.features.runningTree.isLoading(this.state.oakFullpath); Object.assign(data, { oakDirty, - oakExecutable, + // oakExecutable, oakExecuting, oakLoading, }); diff --git a/lib/page.mp.js b/lib/page.mp.js index e8a7b8f0..11f1af3a 100644 --- a/lib/page.mp.js +++ b/lib/page.mp.js @@ -489,7 +489,7 @@ const oakBehavior = Behavior({ this.oakOption.lifetimes?.ready.call(this); const { oakFullpath } = this.state; if (oakFullpath && !this.oakOption.stale && - !this.features.runningTree.checkIsModiNode(oakFullpath) && + !this.features.runningTree.checkIsInModiNextBranch(oakFullpath) && !this.features.runningTree.isListDescandent(oakFullpath)) { this.refresh(); } @@ -794,7 +794,7 @@ function createComponent(option, features) { } const { oakFullpath } = this.state; if (oakFullpath && !option.stale && - !features.runningTree.checkIsModiNode(oakFullpath) && + !features.runningTree.checkIsInModiNextBranch(oakFullpath) && !features.runningTree.isListDescandent(oakFullpath)) { try { await this.refresh(); diff --git a/lib/page.native.d.ts b/lib/page.native.d.ts index a94c1ec6..2f5bea53 100644 --- a/lib/page.native.d.ts +++ b/lib/page.native.d.ts @@ -1,3 +1,4 @@ +import React from 'react'; import { Aspect, EntityDict } from 'oak-domain/lib/types'; import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain'; import { BasicFeatures } from './features'; @@ -5,4 +6,4 @@ import { Feature } from './types/Feature'; import { DataOption, OakComponentOption } from './types/Page'; import { SyncContext } from 'oak-domain/lib/store/SyncRowStore'; import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore'; -export declare function createComponent, FrontCxt extends SyncContext, AD extends Record>>, FD extends Record, FormedData extends Record, TData extends Record = {}, TProperty extends DataOption = {}, TMethod extends Record = {}>(option: OakComponentOption, features: BasicFeatures & FD): any; +export declare function createComponent, FrontCxt extends SyncContext, AD extends Record>>, FD extends Record, FormedData extends Record, TData extends Record = {}, TProperty extends DataOption = {}, TMethod extends Record = {}>(option: OakComponentOption, features: BasicFeatures & FD): React.ForwardRefExoticComponent>; diff --git a/lib/page.react.d.ts b/lib/page.react.d.ts index a3034d03..04b78984 100644 --- a/lib/page.react.d.ts +++ b/lib/page.react.d.ts @@ -1,9 +1,10 @@ +import React from 'react'; import { Aspect, CheckerType, EntityDict, OpRecord } from 'oak-domain/lib/types'; import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain'; import { BasicFeatures } from './features'; import { NamedFilterItem, NamedSorterItem } from './types/NamedCondition'; import { Feature } from './types/Feature'; -import { DataOption, ComponentProps, OakComponentOption, OakNavigateToParameters } from './types/Page'; +import { DataOption, ComponentData, ComponentProps, OakComponentOption, OakNavigateToParameters } from './types/Page'; import { MessageProps } from './types/Message'; import { NotificationProps } from './types/Notification'; import { SyncContext } from 'oak-domain/lib/store/SyncRowStore'; @@ -103,5 +104,23 @@ export declare function createComponent[]) => void): Promise<() => void>; + context: unknown; + setState>(state: ComponentData | ((prevState: Readonly>, props: Readonly>) => ComponentData | Pick, K> | null) | Pick, K> | null, callback?: (() => void) | undefined): void; + forceUpdate(callback?: (() => void) | undefined): void; + readonly props: Readonly>; + state: Readonly>; + refs: { + [key: string]: React.ReactInstance; + }; + shouldComponentUpdate?(nextProps: Readonly>, nextState: Readonly>, nextContext: any): boolean; + componentDidCatch?(error: Error, errorInfo: React.ErrorInfo): void; + getSnapshotBeforeUpdate?(prevProps: Readonly>, prevState: Readonly>): any; + componentWillMount?(): void; + UNSAFE_componentWillMount?(): void; + componentWillReceiveProps?(nextProps: Readonly>, nextContext: any): void; + UNSAFE_componentWillReceiveProps?(nextProps: Readonly>, nextContext: any): void; + componentWillUpdate?(nextProps: Readonly>, nextState: Readonly>, nextContext: any): void; + UNSAFE_componentWillUpdate?(nextProps: Readonly>, nextState: Readonly>, nextContext: any): void; }; + contextType?: React.Context | undefined; }; diff --git a/lib/page.react.js b/lib/page.react.js index cc5c5663..60e35f11 100644 --- a/lib/page.react.js +++ b/lib/page.react.js @@ -652,7 +652,7 @@ function createComponent(option, features) { try { const { oakFullpath } = this.state; if (oakFullpath && !option.stale && - !features.runningTree.checkIsModiNode(oakFullpath) && + !features.runningTree.checkIsInModiNextBranch(oakFullpath) && !features.runningTree.isListDescandent(oakFullpath)) { await this.refresh(); } @@ -712,7 +712,7 @@ function createComponent(option, features) { } const { oakFullpath } = this.state; if (oakFullpath && !option.stale && - !features.runningTree.checkIsModiNode(oakFullpath) && + !features.runningTree.checkIsInModiNextBranch(oakFullpath) && !features.runningTree.isListDescandent(oakFullpath)) { this.refresh(); } diff --git a/lib/page.web.d.ts b/lib/page.web.d.ts index a94c1ec6..2f5bea53 100644 --- a/lib/page.web.d.ts +++ b/lib/page.web.d.ts @@ -1,3 +1,4 @@ +import React from 'react'; import { Aspect, EntityDict } from 'oak-domain/lib/types'; import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain'; import { BasicFeatures } from './features'; @@ -5,4 +6,4 @@ import { Feature } from './types/Feature'; import { DataOption, OakComponentOption } from './types/Page'; import { SyncContext } from 'oak-domain/lib/store/SyncRowStore'; import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore'; -export declare function createComponent, FrontCxt extends SyncContext, AD extends Record>>, FD extends Record, FormedData extends Record, TData extends Record = {}, TProperty extends DataOption = {}, TMethod extends Record = {}>(option: OakComponentOption, features: BasicFeatures & FD): any; +export declare function createComponent, FrontCxt extends SyncContext, AD extends Record>>, FD extends Record, FormedData extends Record, TData extends Record = {}, TProperty extends DataOption = {}, TMethod extends Record = {}>(option: OakComponentOption, features: BasicFeatures & FD): React.ForwardRefExoticComponent>; diff --git a/lib/page.web.js b/lib/page.web.js index 28223b2f..ca1bd151 100644 --- a/lib/page.web.js +++ b/lib/page.web.js @@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.createComponent = void 0; const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); -const react_1 = tslib_1.__importDefault(require("react")); const withRouter_1 = tslib_1.__importDefault(require("./platforms/web/router/withRouter")); const PullToRefresh_1 = tslib_1.__importDefault(require("./platforms/web/PullToRefresh")); const page_react_1 = require("./page.react"); diff --git a/lib/platforms/native/features/index.d.ts b/lib/platforms/native/features/index.d.ts index 61a6578a..ed07a4f1 100644 --- a/lib/platforms/native/features/index.d.ts +++ b/lib/platforms/native/features/index.d.ts @@ -4,6 +4,6 @@ type Props = { features: Record; children: React.ReactNode; }; -declare const FeaturesProvider: (props: Props) => any; -declare const useFeatures: >() => any; +declare const FeaturesProvider: (props: Props) => import("react/jsx-runtime").JSX.Element; +declare const useFeatures: >() => FD2; export { FeaturesProvider, useFeatures }; diff --git a/lib/platforms/native/router/withRouter.d.ts b/lib/platforms/native/router/withRouter.d.ts index 21857320..5eda84fb 100644 --- a/lib/platforms/native/router/withRouter.d.ts +++ b/lib/platforms/native/router/withRouter.d.ts @@ -1,6 +1,7 @@ +import React from 'react'; type OakComponentProperties = { path?: string; properties?: Record; }; -declare const withRouter: (Component: React.ComponentType, { path, properties }: OakComponentProperties) => any; +declare const withRouter: (Component: React.ComponentType, { path, properties }: OakComponentProperties) => React.ForwardRefExoticComponent>; export default withRouter; diff --git a/lib/platforms/web/Loading.d.ts b/lib/platforms/web/Loading.d.ts index 6cf00498..9a4eb5de 100644 --- a/lib/platforms/web/Loading.d.ts +++ b/lib/platforms/web/Loading.d.ts @@ -1,3 +1,4 @@ +import React from 'react'; import 'nprogress/nprogress.css'; -declare const _default: any; +declare const _default: React.MemoExoticComponent<() => null>; export default _default; diff --git a/lib/platforms/web/PullToRefresh.js b/lib/platforms/web/PullToRefresh.js index cbab5c59..a2170211 100644 --- a/lib/platforms/web/PullToRefresh.js +++ b/lib/platforms/web/PullToRefresh.js @@ -2,7 +2,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); -const react_1 = tslib_1.__importDefault(require("react")); const rmc_pull_to_refresh_1 = tslib_1.__importDefault(require("rmc-pull-to-refresh")); require("./PullToRefresh.css"); const OakPullToRefresh = (props) => { diff --git a/lib/platforms/web/features/index.d.ts b/lib/platforms/web/features/index.d.ts index 08182f40..18e3356a 100644 --- a/lib/platforms/web/features/index.d.ts +++ b/lib/platforms/web/features/index.d.ts @@ -4,5 +4,5 @@ declare const FeaturesProvider: React.FC<{ features: Record; children: React.ReactNode; }>; -declare const useFeatures: >() => any; +declare const useFeatures: >() => FD2; export { FeaturesProvider, useFeatures }; diff --git a/lib/platforms/web/initialize/AppContainer.d.ts b/lib/platforms/web/initialize/AppContainer.d.ts index 22b5a939..03e1966b 100644 --- a/lib/platforms/web/initialize/AppContainer.d.ts +++ b/lib/platforms/web/initialize/AppContainer.d.ts @@ -2,5 +2,5 @@ import React from 'react'; type AppContainerProps = { children?: React.ReactNode; }; -declare const AppContainer: (props: AppContainerProps) => any; +declare const AppContainer: (props: AppContainerProps) => import("react/jsx-runtime").JSX.Element; export default AppContainer; diff --git a/lib/platforms/web/initialize/AppError.d.ts b/lib/platforms/web/initialize/AppError.d.ts index 300bfc4f..f0499037 100644 --- a/lib/platforms/web/initialize/AppError.d.ts +++ b/lib/platforms/web/initialize/AppError.d.ts @@ -5,5 +5,5 @@ interface ErrorProps { error: any; features: BasicFeatures; } -declare function Error(props: ErrorProps): any; +declare function Error(props: ErrorProps): import("react/jsx-runtime").JSX.Element; export default Error; diff --git a/lib/platforms/web/initialize/AppError.js b/lib/platforms/web/initialize/AppError.js index 111ce68b..a5ac51c3 100644 --- a/lib/platforms/web/initialize/AppError.js +++ b/lib/platforms/web/initialize/AppError.js @@ -1,12 +1,34 @@ "use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; Object.defineProperty(exports, "__esModule", { value: true }); -const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); -const react_1 = tslib_1.__importStar(require("react")); +const react_1 = require("react"); const antd_1 = require("antd"); const Exception_1 = require("oak-domain/lib/types/Exception"); const ErrorPage_1 = require("../../../types/ErrorPage"); -const ErrorPage = (0, react_1.lazy)(() => Promise.resolve().then(() => tslib_1.__importStar(require('../../../components/errorPage')))); +const ErrorPage = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('../../../components/errorPage')))); function Error(props) { const { error, features } = props; if (error instanceof Exception_1.OakException) { diff --git a/lib/platforms/web/initialize/AppRouter.d.ts b/lib/platforms/web/initialize/AppRouter.d.ts index d6b79bba..b7620d11 100644 --- a/lib/platforms/web/initialize/AppRouter.d.ts +++ b/lib/platforms/web/initialize/AppRouter.d.ts @@ -5,5 +5,5 @@ declare const AppRouter: (props: { routers: IRouter[]; appName: string; features: BasicFeatures; -}) => any; +}) => import("react/jsx-runtime").JSX.Element; export default AppRouter; diff --git a/lib/platforms/web/initialize/index.js b/lib/platforms/web/initialize/index.js index 9ea67293..62f99595 100644 --- a/lib/platforms/web/initialize/index.js +++ b/lib/platforms/web/initialize/index.js @@ -2,8 +2,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); -// @ts-nocheck -const react_1 = tslib_1.__importDefault(require("react")); const client_1 = tslib_1.__importDefault(require("react-dom/client")); const history_1 = require("history"); const react_router_dom_1 = require("react-router-dom"); diff --git a/lib/platforms/web/responsive/context.d.ts b/lib/platforms/web/responsive/context.d.ts index 0fded541..08e5d73e 100644 --- a/lib/platforms/web/responsive/context.d.ts +++ b/lib/platforms/web/responsive/context.d.ts @@ -1,3 +1,4 @@ +import React from 'react'; export type Width = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'; export type Keys = Width[]; export type Values = { @@ -15,4 +16,6 @@ export type Breakpoints = { export declare const keys: Keys; export declare const values: Values; export declare const defaultBreakpoints: Breakpoints; -export declare const ResponsiveContext: any; +export declare const ResponsiveContext: React.Context<{ + breakpoints?: Breakpoints | undefined; +}>; diff --git a/lib/platforms/web/router/withRouter.d.ts b/lib/platforms/web/router/withRouter.d.ts index 21857320..5eda84fb 100644 --- a/lib/platforms/web/router/withRouter.d.ts +++ b/lib/platforms/web/router/withRouter.d.ts @@ -1,6 +1,7 @@ +import React from 'react'; type OakComponentProperties = { path?: string; properties?: Record; }; -declare const withRouter: (Component: React.ComponentType, { path, properties }: OakComponentProperties) => any; +declare const withRouter: (Component: React.ComponentType, { path, properties }: OakComponentProperties) => React.ForwardRefExoticComponent>; export default withRouter; diff --git a/lib/types/Page.d.ts b/lib/types/Page.d.ts index 6ad77f43..7cdaba98 100644 --- a/lib/types/Page.d.ts +++ b/lib/types/Page.d.ts @@ -325,7 +325,6 @@ export type OakComponentOnlyMethods = { setOakActions: () => void; }; export type OakComponentData = { - oakExecutable: boolean | Error; oakExecuting: boolean; oakFocused: { attr: string; diff --git a/src/cacheStore/CacheStore.ts b/src/cacheStore/CacheStore.ts index d749a0aa..527fd3dd 100644 --- a/src/cacheStore/CacheStore.ts +++ b/src/cacheStore/CacheStore.ts @@ -3,7 +3,7 @@ import { StorageSchema } from "oak-domain/lib/types/Storage"; import { readOnlyActions } from 'oak-domain/lib/actions/action'; import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain'; import { Checker, CheckerType, Trigger, TxnOption } from 'oak-domain/lib/types'; -import { TreeStore, TreeStoreOperateOption } from 'oak-memory-tree-store'; +import { TreeStore, TreeStoreOperateOption, TreeStoreSelectOption } from 'oak-memory-tree-store'; import { assert } from 'oak-domain/lib/utils/assert'; import { SyncContext, SyncRowStore } from 'oak-domain/lib/store/SyncRowStore'; import SyncTriggerExecutor from './SyncTriggerExecutor'; @@ -73,7 +73,7 @@ export class CacheStore extends TreeStor select< T extends keyof ED, - OP extends SelectOption, + OP extends TreeStoreSelectOption, Cxt extends SyncContext >(entity: T, selection: ED[T]['Selection'], context: Cxt, option: OP) { assert(context.getCurrentTxnId()); diff --git a/src/components/relation/path/upsert/web.pc.tsx b/src/components/relation/path/upsert/web.pc.tsx index b68e4154..2fd24d87 100644 --- a/src/components/relation/path/upsert/web.pc.tsx +++ b/src/components/relation/path/upsert/web.pc.tsx @@ -33,6 +33,7 @@ export default function render( recursivable: boolean; legalSourceEntity: boolean; destEntityFixed: boolean; + oakExecutable: boolean | Error; }, { updateDestEntity: (de: string) => void; @@ -186,7 +187,7 @@ export default function render( diff --git a/src/features/runningTree.ts b/src/features/runningTree.ts index c7fababb..e69dc8aa 100644 --- a/src/features/runningTree.ts +++ b/src/features/runningTree.ts @@ -862,7 +862,7 @@ class ListNode< } } - getFreshValue(inModi?: boolean): Array> { + getFreshValue(inModiNextBranch?: boolean): Array> { /** * 现在简化情况,只取sr中有id的数据,以及addItem中的create数据 * 但是对于modi查询,需要查询“热更新”部分的数据(因为这部分数据不会被sync到内存中,逻辑不严密,后面再说) @@ -880,7 +880,7 @@ class ListNode< /** * 在非modi状态下,所取数据是在ids2中满足filter的部分(自身对象和其它对象的更新可能会影响这些行不再满足条件) */ - const filter2 = inModi ? filter : (ids2.length > 0 ? combineFilters( + const filter2 = inModiNextBranch ? filter : (ids2.length > 0 ? combineFilters( this.entity, this.cache.getSchema(), [filter, { @@ -892,7 +892,7 @@ class ListNode< if (filter2 && data) { const result = this.cache.get(this.entity, { data, - filter: inModi ? filter : filter2, + filter: inModiNextBranch ? filter : filter2, sorter, }, this.sr); @@ -2291,41 +2291,33 @@ export class RunningTree extends Feature return node; } - private checkSingleNodeIsModiNode(node: SingleNode) { - const id = node.getId(); - if (id) { - const modies = this.cache.get('modi', { - data: { - id: 1, - }, - filter: { - targetEntity: node.getEntity() as string, - action: 'create', - data: { - id, - }, - iState: 'active', - } - }); - return modies.length > 0; - } - return false; - } - - checkIsModiNode(path: string) { + // 判断当前结点是否在:next的路径上(且有前项结点,两者同时满足就不用refresh了) + checkIsInModiNextBranch(path: string) { if (!path.includes(MODI_NEXT_PATH_SUFFIX)) { return false; } - const node = this.findNode(path); - if (node instanceof SingleNode) { - return this.checkSingleNodeIsModiNode(node); + const paths = path.split('.'); + + if (paths[0].includes(MODI_NEXT_PATH_SUFFIX)) { + // 根结点就是:next,这时候还是要取的 + return false; } - else { - assert(node instanceof ListNode); - const parent = node.getParent(); - assert(parent instanceof SingleNode); - return this.checkSingleNodeIsModiNode(parent); + let iter = 1; + while(iter < paths.length) { + if (paths[iter].includes(MODI_NEXT_PATH_SUFFIX)) { + const path2 = paths.slice(0, iter) + paths[iter].replace(MODI_NEXT_PATH_SUFFIX, ''); + + const node = this.findNode(path2); + if (node) { + return true; + } + return false; + } + iter ++; } + + assert(false); + return false; } private findNode(path: string) { @@ -2376,33 +2368,11 @@ export class RunningTree extends Feature return this.cache.begin()!; } - redoBranchOperations(path: string) { - const paths = path.split('.'); - const root = paths.shift(); - - const rootNode = this.root[root!]; - const opers = rootNode.composeOperations(paths); - if (opers) { - this.cache.redoOperation(opers); - } - } - - redoBranchModis(path: string) { - const { root } = analyzePath(path); - - const rootNode = this.root[root]; - const includeModi = path.includes(MODI_NEXT_PATH_SUFFIX); - if (includeModi) { - const modiOperations = rootNode.getModiOperations(); - modiOperations && this.cache.redoOperation(modiOperations); - } - } - getFreshValue(path: string) { const node = this.findNode(path); if (node instanceof ListNode) { - const includeModi = path.includes(MODI_NEXT_PATH_SUFFIX); - return node.getFreshValue(includeModi); + const inModiNextBranch = path.includes(MODI_NEXT_PATH_SUFFIX) && !path.endsWith(MODI_NEXT_PATH_SUFFIX); + return node.getFreshValue(inModiNextBranch); } assert(node instanceof SingleNode); return node.getFreshValue(); @@ -2724,6 +2694,51 @@ export class RunningTree extends Feature return operations; } + private cachedOperations: Record = {}; + + private cachedModis: Record = {}; + + /** + * 这个函数在reRender时可能会反复调用,composeOperations很消耗性能,在这里要做个缓存 + * @param path + */ + redoBranchOperations(path: string) { + const paths = path.split('.'); + const root = paths.shift(); + + const rootNode = this.root[root!]; + + const opers = rootNode.composeOperations(paths); + if (opers) { + this.cache.redoOperation(opers); + } + } + + /** + * 这个函数在reRender时可能会反复调用,getModiOperations很消耗性能,在这里要做个缓存 + * @param path + */ + redoBranchModis(path: string) { + const { root } = analyzePath(path); + + const rootNode = this.root[root]; + const includeModi = path.includes(MODI_NEXT_PATH_SUFFIX); + if (includeModi) { + const modiOperations = rootNode.getModiOperations(); + modiOperations && this.cache.redoOperation(modiOperations); + } + } + + tryExecute(path: string, action?: string) { + + } + async execute(path: string, action?: ED[T]['Action'], opers?: Array<{ entity: keyof ED, operation: ED[keyof ED]['Operation'], @@ -2735,7 +2750,7 @@ export class RunningTree extends Feature let pollute = false; try { - let operations = node.composeOperations() || []; + let operations = this.getOperations(path) || []; if (opers) { operations.push(...opers); } diff --git a/src/page.common.ts b/src/page.common.ts index 7b40b65d..26a2a87e 100644 --- a/src/page.common.ts +++ b/src/page.common.ts @@ -518,7 +518,8 @@ export function reRender< const oakLoadingMore = this.features.runningTree.isLoadingMore(this.state.oakFullpath); const oakLoading = !oakLoadingMore && this.features.runningTree.isLoading(this.state.oakFullpath); const oakExecuting = this.features.runningTree.isExecuting(this.state.oakFullpath); - const oakExecutable = !oakExecuting && this.tryExecute(); + // 这个很耗时,让用户去相应要execute的页面上调用 + // const oakExecutable = !oakExecuting && this.tryExecute(); // 现在取数据需要把runningTree上的更新应用了再取,判定actions也一样 let rollback = this.features.runningTree.begin(); try { @@ -599,7 +600,6 @@ export function reRender< } }; Object.assign(data, { - oakExecutable, oakDirty, oakLoading, oakLoadingMore, @@ -635,11 +635,11 @@ export function reRender< */ const oakDirty = this.features.runningTree.isDirty(this.state.oakFullpath); const oakExecuting = this.features.runningTree.isExecuting(this.state.oakFullpath); - const oakExecutable = !oakExecuting && this.tryExecute(); + // const oakExecutable = !oakExecuting && this.tryExecute(); const oakLoading = this.features.runningTree.isLoading(this.state.oakFullpath); Object.assign(data, { oakDirty, - oakExecutable, + // oakExecutable, oakExecuting, oakLoading, }); diff --git a/src/page.mp.ts b/src/page.mp.ts index 556c2e2f..5175c124 100644 --- a/src/page.mp.ts +++ b/src/page.mp.ts @@ -711,7 +711,7 @@ const oakBehavior = Behavior< const { oakFullpath } = this.state; if ( oakFullpath && !this.oakOption.stale && - !this.features.runningTree.checkIsModiNode( + !this.features.runningTree.checkIsInModiNextBranch( oakFullpath ) && !this.features.runningTree.isListDescandent( @@ -1122,7 +1122,7 @@ export function createComponent< } const { oakFullpath } = this.state; if (oakFullpath && !option.stale && - !features.runningTree.checkIsModiNode(oakFullpath) && + !features.runningTree.checkIsInModiNextBranch(oakFullpath) && !features.runningTree.isListDescandent(oakFullpath)) { try { await this.refresh(); diff --git a/src/page.react.tsx b/src/page.react.tsx index f9bca062..5a7c58bb 100644 --- a/src/page.react.tsx +++ b/src/page.react.tsx @@ -980,7 +980,7 @@ export function createComponent< try { const { oakFullpath } = this.state; if (oakFullpath && !option.stale && - !features.runningTree.checkIsModiNode(oakFullpath) && + !features.runningTree.checkIsInModiNextBranch(oakFullpath) && !features.runningTree.isListDescandent(oakFullpath)) { await this.refresh(); } @@ -1050,7 +1050,7 @@ export function createComponent< } const { oakFullpath } = this.state; if (oakFullpath && !option.stale && - !features.runningTree.checkIsModiNode(oakFullpath) && + !features.runningTree.checkIsInModiNextBranch(oakFullpath) && !features.runningTree.isListDescandent(oakFullpath)) { this.refresh(); } diff --git a/src/types/Page.ts b/src/types/Page.ts index 4802feab..e70cf1a7 100644 --- a/src/types/Page.ts +++ b/src/types/Page.ts @@ -558,7 +558,7 @@ export type OakComponentData< ED extends EntityDict & BaseEntityDict, T extends keyof ED > = { - oakExecutable: boolean | Error; + // oakExecutable: boolean | Error; oakExecuting: boolean; oakFocused: { attr: string;