From ad2db18b64f57d6502e189ddc7eb68a29aa87f8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E7=86=A0?= Date: Fri, 10 Sep 2021 10:26:49 +0800 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=BE=AA=E7=8E=AF?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E6=97=B6loop:=20[]=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/vision-polyfill/src/props-reducers/index.ts | 1 + .../props-reducers/reset-loop-default-value-reducer.ts | 10 ++++++++++ packages/vision-polyfill/src/reducers.ts | 4 ++++ 3 files changed, 15 insertions(+) create mode 100644 packages/vision-polyfill/src/props-reducers/reset-loop-default-value-reducer.ts diff --git a/packages/vision-polyfill/src/props-reducers/index.ts b/packages/vision-polyfill/src/props-reducers/index.ts index 148d115b7..2684f6b96 100644 --- a/packages/vision-polyfill/src/props-reducers/index.ts +++ b/packages/vision-polyfill/src/props-reducers/index.ts @@ -6,3 +6,4 @@ export * from './remove-empty-prop-reducer'; export * from './style-reducer'; export * from './upgrade-reducer'; export * from './node-top-fixed-reducer'; +export * from './reset-loop-default-value-reducer'; diff --git a/packages/vision-polyfill/src/props-reducers/reset-loop-default-value-reducer.ts b/packages/vision-polyfill/src/props-reducers/reset-loop-default-value-reducer.ts new file mode 100644 index 000000000..fc5036e99 --- /dev/null +++ b/packages/vision-polyfill/src/props-reducers/reset-loop-default-value-reducer.ts @@ -0,0 +1,10 @@ +// 讲loop=[]的情况处理成loop=false +export function resetLoopDefaultValueReducer(props: any) { + if (props.loop && Array.isArray(props.loop) && props.loop.length === 0) { + return { + ...props, + loop: undefined, + }; + } + return props; +} diff --git a/packages/vision-polyfill/src/reducers.ts b/packages/vision-polyfill/src/reducers.ts index 8c5f488b3..5bc04e35d 100644 --- a/packages/vision-polyfill/src/reducers.ts +++ b/packages/vision-polyfill/src/reducers.ts @@ -14,6 +14,7 @@ import { initNodeReducer, liveLifecycleReducer, nodeTopFixedReducer, + resetLoopDefaultValueReducer, } from './props-reducers'; const { LiveEditing, TransformStage } = designerCabin; @@ -57,3 +58,6 @@ designer.addPropsReducer(removeEmptyPropsReducer, TransformStage.Save); designer.addPropsReducer(nodeTopFixedReducer, TransformStage.Render); designer.addPropsReducer(nodeTopFixedReducer, TransformStage.Save); + +// loop的默认值处理 +designer.addPropsReducer(resetLoopDefaultValueReducer, TransformStage.Save); From 88508294233e4f3a71018c7eb7cf07be14219a1a Mon Sep 17 00:00:00 2001 From: "lihao.ylh" Date: Tue, 14 Sep 2021 11:16:41 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E4=BC=A0?= =?UTF-8?q?=E5=85=A5=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9A=84=E7=94=BB=E5=B8=83?= =?UTF-8?q?=20Loading=20=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/designer/src/project/project-view.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/project/project-view.tsx b/packages/designer/src/project/project-view.tsx index e3f32f4e2..4e0d64998 100644 --- a/packages/designer/src/project/project-view.tsx +++ b/packages/designer/src/project/project-view.tsx @@ -1,10 +1,10 @@ import { Component } from 'react'; -import { observer } from '@ali/lowcode-editor-core'; +import { observer, engineConfig } from '@ali/lowcode-editor-core'; import { Designer } from '../designer'; import { BuiltinSimulatorHostView } from '../builtin-simulator'; import './project.less'; -class Loading extends Component { +class BuiltinLoading extends Component { render() { return (
@@ -29,6 +29,7 @@ export class ProjectView extends Component<{ designer: Designer }> { const { project } = designer; const { simulatorProps } = project; const Simulator = designer.simulatorComponent || BuiltinSimulatorHostView; + const Loading = engineConfig.get('loadingComponent', BuiltinLoading); return (
From fc7c78387f7db5aa7a725934b10d0ee8d8f23826 Mon Sep 17 00:00:00 2001 From: "lihao.ylh" Date: Tue, 14 Sep 2021 11:17:25 +0800 Subject: [PATCH 3/5] =?UTF-8?q?refactor:=20=E8=B0=83=E6=95=B4=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E5=8C=BA=E9=9D=A2=E5=8C=85=E5=B1=91=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/settings/settings-primary-pane.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx index a3da762aa..9e6e4c32a 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -229,6 +229,7 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any return (
+ { this.renderBreadcrumb() } { @@ -238,7 +239,6 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any animation={false} excessMode="dropdown" contentClassName="lc-settings-tabs-content" - extra={this.renderBreadcrumb()} > {tabs} From e3874bbbac463816763ad8e8315576b3d9801278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E7=86=A0?= Date: Fri, 10 Sep 2021 10:26:49 +0800 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=BE=AA=E7=8E=AF?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E6=97=B6loop:=20[]=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/vision-polyfill/src/props-reducers/index.ts | 1 + .../props-reducers/reset-loop-default-value-reducer.ts | 10 ++++++++++ packages/vision-polyfill/src/reducers.ts | 4 ++++ 3 files changed, 15 insertions(+) create mode 100644 packages/vision-polyfill/src/props-reducers/reset-loop-default-value-reducer.ts diff --git a/packages/vision-polyfill/src/props-reducers/index.ts b/packages/vision-polyfill/src/props-reducers/index.ts index 148d115b7..2684f6b96 100644 --- a/packages/vision-polyfill/src/props-reducers/index.ts +++ b/packages/vision-polyfill/src/props-reducers/index.ts @@ -6,3 +6,4 @@ export * from './remove-empty-prop-reducer'; export * from './style-reducer'; export * from './upgrade-reducer'; export * from './node-top-fixed-reducer'; +export * from './reset-loop-default-value-reducer'; diff --git a/packages/vision-polyfill/src/props-reducers/reset-loop-default-value-reducer.ts b/packages/vision-polyfill/src/props-reducers/reset-loop-default-value-reducer.ts new file mode 100644 index 000000000..fc5036e99 --- /dev/null +++ b/packages/vision-polyfill/src/props-reducers/reset-loop-default-value-reducer.ts @@ -0,0 +1,10 @@ +// 讲loop=[]的情况处理成loop=false +export function resetLoopDefaultValueReducer(props: any) { + if (props.loop && Array.isArray(props.loop) && props.loop.length === 0) { + return { + ...props, + loop: undefined, + }; + } + return props; +} diff --git a/packages/vision-polyfill/src/reducers.ts b/packages/vision-polyfill/src/reducers.ts index 8c5f488b3..5bc04e35d 100644 --- a/packages/vision-polyfill/src/reducers.ts +++ b/packages/vision-polyfill/src/reducers.ts @@ -14,6 +14,7 @@ import { initNodeReducer, liveLifecycleReducer, nodeTopFixedReducer, + resetLoopDefaultValueReducer, } from './props-reducers'; const { LiveEditing, TransformStage } = designerCabin; @@ -57,3 +58,6 @@ designer.addPropsReducer(removeEmptyPropsReducer, TransformStage.Save); designer.addPropsReducer(nodeTopFixedReducer, TransformStage.Render); designer.addPropsReducer(nodeTopFixedReducer, TransformStage.Save); + +// loop的默认值处理 +designer.addPropsReducer(resetLoopDefaultValueReducer, TransformStage.Save); From f8584e101afb89b672fca8ea6a1836db7626c67e Mon Sep 17 00:00:00 2001 From: "lihao.ylh" Date: Mon, 6 Sep 2021 14:19:08 +0800 Subject: [PATCH 5/5] =?UTF-8?q?refactor:=20=E5=B0=86=20obx=20=E6=8D=A2?= =?UTF-8?q?=E6=88=90=20mobx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/designer/jest.config.js | 2 +- .../bem-tools/border-detecting.tsx | 4 - .../bem-tools/border-resizing.tsx | 8 -- .../bem-tools/border-selecting.tsx | 14 +-- .../src/builtin-simulator/bem-tools/index.tsx | 4 - .../builtin-simulator/bem-tools/insertion.tsx | 4 - .../designer/src/builtin-simulator/host.ts | 39 +++++--- .../src/builtin-simulator/viewport.ts | 6 +- packages/designer/src/designer/designer.ts | 9 +- packages/designer/src/designer/detecting.ts | 6 +- .../src/designer/drag-ghost/index.tsx | 7 +- packages/designer/src/designer/dragon.ts | 6 +- .../designer/src/designer/offset-observer.ts | 5 +- .../src/designer/setting/setting-field.ts | 7 +- .../designer/setting/setting-prop-entry.ts | 47 ++++----- .../designer/src/document/document-model.ts | 19 ++-- .../designer/src/document/document-view.tsx | 4 - packages/designer/src/document/history.ts | 27 +++--- .../src/document/node/exclusive-group.ts | 5 +- .../src/document/node/node-children.ts | 11 ++- packages/designer/src/document/node/node.ts | 32 +++--- .../src/document/node/props/prop-stash.ts | 9 +- .../designer/src/document/node/props/prop.ts | 69 +++++++------ .../designer/src/document/node/props/props.ts | 97 +++++++------------ packages/designer/src/document/selection.ts | 8 +- packages/designer/src/project/project.ts | 6 +- .../tests/builtin-simulator/host.test.ts | 2 +- .../tests/document/node/props/prop.test.ts | 4 +- .../tests/main/meta/component-meta.test.ts | 14 ++- packages/editor-core/package.json | 6 +- packages/editor-core/src/editor.ts | 2 +- packages/editor-core/src/intl/index.ts | 7 +- packages/editor-core/src/utils/obx.ts | 23 ++++- packages/editor-skeleton/src/area.ts | 5 +- .../src/components/array-setter/index.tsx | 10 +- .../src/components/settings/main.ts | 5 +- .../src/components/settings/settings-pane.tsx | 11 +-- .../settings/settings-primary-pane.tsx | 11 ++- .../src/components/widget-views/index.tsx | 12 --- .../widget-views/panel-operation-row.tsx | 6 ++ .../src/layouts/bottom-area.tsx | 4 - .../editor-skeleton/src/layouts/left-area.tsx | 2 +- .../src/layouts/left-fixed-pane.tsx | 11 +-- .../src/layouts/left-float-pane.tsx | 9 -- .../editor-skeleton/src/layouts/main-area.tsx | 4 - .../src/layouts/right-area.tsx | 4 - .../editor-skeleton/src/layouts/top-area.tsx | 2 +- .../editor-skeleton/src/layouts/workbench.tsx | 4 - packages/editor-skeleton/src/widget/dock.ts | 3 +- .../editor-skeleton/src/widget/panel-dock.ts | 3 +- packages/editor-skeleton/src/widget/panel.ts | 9 +- .../src/widget/widget-container.ts | 11 ++- packages/editor-skeleton/src/widget/widget.ts | 3 +- packages/plugin-outline-pane/src/main.ts | 7 +- .../plugin-outline-pane/src/tree-master.ts | 7 +- packages/plugin-outline-pane/src/tree-node.ts | 7 +- packages/plugin-outline-pane/src/tree.ts | 3 +- .../plugin-outline-pane/src/views/pane.tsx | 4 - .../src/views/root-tree-node.tsx | 8 -- .../src/views/tree-branches.tsx | 12 --- .../src/views/tree-node.tsx | 4 - .../src/views/tree-title.tsx | 12 --- packages/rax-simulator-renderer/package.json | 4 +- .../rax-simulator-renderer/src/renderer.ts | 8 +- .../react-simulator-renderer/package.json | 4 +- .../react-simulator-renderer/src/index.ts | 11 ++- .../src/renderer-view.tsx | 10 +- .../react-simulator-renderer/src/renderer.ts | 32 ++++-- packages/vision-polyfill/src/env.ts | 2 +- .../vision-polyfill/src/fields/fields.tsx | 4 +- .../vision-polyfill/src/i18n-util/index.js | 2 +- tsconfig.json | 4 +- 72 files changed, 363 insertions(+), 424 deletions(-) diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index e36463ad3..6e872af60 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -6,7 +6,7 @@ module.exports = { // // '^.+\\.(ts|tsx)$': 'ts-jest', // // '^.+\\.(js|jsx)$': 'babel-jest', // }, - // testMatch: ['**/node.test.ts'], + // testMatch: ['**/prop.test.ts'], // testMatch: ['(/tests?/.*(test))\\.[jt]s$'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx index c546ca9f9..37602d28f 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx @@ -46,10 +46,6 @@ export class BorderDetectingInstance extends PureComponent<{ @observer export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> { - shouldComponentUpdate() { - return false; - } - @computed get scale() { return this.props.host.viewport.scale; } diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx index 76c3ac7b7..b870aef7d 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx @@ -28,10 +28,6 @@ export default class BoxResizing extends Component<{ host: BuiltinSimulatorHost return this.dragging ? selection.getTopNodes() : selection.getNodes(); } - shouldComponentUpdate() { - return false; - } - componentDidUpdate() { // this.hoveringCapture.setBoundary(this.outline); // this.willBind(); @@ -73,10 +69,6 @@ export class BoxResizingForNode extends Component<{ host: BuiltinSimulatorHost; return this.host.getComponentInstances(this.props.node); } - shouldComponentUpdate() { - return false; - } - render() { const { instances } = this; const { node } = this.props; diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx index ea21f820b..bb0b1b6d3 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -9,7 +9,7 @@ import { ComponentType, } from 'react'; import classNames from 'classnames'; -import { observer, computed, Tip, globalContext, Editor } from '@ali/lowcode-editor-core'; +import { observer, computed, Tip, globalContext, makeObservable } from '@ali/lowcode-editor-core'; import { createIcon, isReactComponent } from '@ali/lowcode-utils'; import { ActionContentObject, isActionContentObject } from '@ali/lowcode-types'; import { BuiltinSimulatorHost } from '../host'; @@ -62,10 +62,6 @@ export class BorderSelectingInstance extends Component<{ @observer class Toolbar extends Component<{ observed: OffsetObserver }> { - shouldComponentUpdate() { - return false; - } - render() { const { observed } = this.props; const { height, width } = observed.viewport; @@ -169,10 +165,6 @@ export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHo return this.host.getComponentInstances(this.props.node); } - shouldComponentUpdate() { - return false; - } - render() { const { instances } = this; const { node } = this.props; @@ -217,10 +209,6 @@ export class BorderSelecting extends Component<{ host: BuiltinSimulatorHost }> { return this.dragging ? selection.getTopNodes() : selection.getNodes(); } - shouldComponentUpdate() { - return false; - } - render() { const { selecting } = this; if (!selecting || selecting.length < 1) { diff --git a/packages/designer/src/builtin-simulator/bem-tools/index.tsx b/packages/designer/src/builtin-simulator/bem-tools/index.tsx index 6551633e8..e5d11a8e3 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/index.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/index.tsx @@ -11,10 +11,6 @@ import './borders.less'; @observer export class BemTools extends Component<{ host: BuiltinSimulatorHost }> { - shouldComponentUpdate() { - return false; - } - render() { const { host } = this.props; const { designMode } = host; diff --git a/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx b/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx index cb014c827..5b14f6a40 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx @@ -116,10 +116,6 @@ function processDetail({ target, detail, document }: DropLocation): InsertionDat @observer export class InsertionView extends Component<{ host: BuiltinSimulatorHost }> { - shouldComponentUpdate() { - return false; - } - render() { const { host } = this.props; const loc = host.currentDocument?.dropLocation; diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 713f47247..fc5a36873 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -1,11 +1,16 @@ import { obx, autorun, + reaction, computed, getPublicPath, hotkey, focusTracker, engineConfig, + IReactionPublic, + IReactionOptions, + IReactionDisposer, + makeObservable, } from '@ali/lowcode-editor-core'; import { EventEmitter } from 'events'; import { @@ -164,16 +169,27 @@ export class BuiltinSimulatorHost implements ISimulatorHost(() => this.componentsAsset); + this.injectionConsumer = new ResourceConsumer(() => { + return { + i18n: this.project.i18n, + }; + }); } get currentDocument() { @@ -256,22 +272,25 @@ export class BuiltinSimulatorHost implements ISimulatorHost void; firstRun: boolean }) => void, + effect: (reaction: IReactionPublic) => void, options?: IReactionOptions, ) { this._renderer = renderer; - return autorun(fn as any, true); + return autorun(effect, options); } - autorun(fn: (context: { dispose: () => void; firstRun: boolean }) => void) { - return autorun(fn as any, true); + reaction(expression: (reaction: IReactionPublic) => unknown, effect: (value: unknown, prev: unknown, reaction: IReactionPublic) => void, + opts?: IReactionOptions | undefined): IReactionDisposer { + return reaction(expression, effect, opts); + } + + autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions): IReactionDisposer { + return autorun(effect, options); } purge(): void { // todo } - readonly viewport = new Viewport(); - mountViewport(viewport: Element | null) { this.viewport.mount(viewport); } @@ -294,14 +313,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost(() => this.componentsAsset); - - readonly injectionConsumer = new ResourceConsumer(() => { - return { - i18n: this.project.i18n, - }; - }); - readonly asyncLibraryMap: { [key: string]: {} } = {}; readonly libraryMap: { [key: string]: string } = {}; diff --git a/packages/designer/src/builtin-simulator/viewport.ts b/packages/designer/src/builtin-simulator/viewport.ts index 0362a1332..c5c6d18aa 100644 --- a/packages/designer/src/builtin-simulator/viewport.ts +++ b/packages/designer/src/builtin-simulator/viewport.ts @@ -1,4 +1,4 @@ -import { obx, computed } from '@ali/lowcode-editor-core'; +import { obx, computed, makeObservable } from '@ali/lowcode-editor-core'; import { Point, ScrollTarget } from '../designer'; import { AutoFit, IViewport } from '../simulator'; @@ -25,6 +25,10 @@ export default class Viewport implements IViewport { private viewportElement?: HTMLElement; + constructor() { + makeObservable(this); + } + mount(viewportElement: HTMLElement | null) { if (!viewportElement || this.viewportElement === viewportElement) { return; diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 76db5e882..4ec376510 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -1,5 +1,5 @@ import { ComponentType } from 'react'; -import { obx, computed, autorun } from '@ali/lowcode-editor-core'; +import { obx, computed, autorun, makeObservable, IReactionPublic, IReactionOptions, IReactionDisposer } from '@ali/lowcode-editor-core'; import { ProjectSchema, ComponentMetadata, @@ -71,6 +71,7 @@ export class Designer { } constructor(props: DesignerProps) { + makeObservable(this); const { editor } = props; this.editor = editor; this.setProps(props); @@ -563,12 +564,12 @@ export class Designer { } } - autorun(action: (context: { firstRun: boolean }) => void, sync = false): () => void { - return autorun(action, sync as true); + autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions): IReactionDisposer { + return autorun(effect, options); } purge() { - // todo: + // TODO: } } diff --git a/packages/designer/src/designer/detecting.ts b/packages/designer/src/designer/detecting.ts index 889d7e817..92f0ceb17 100644 --- a/packages/designer/src/designer/detecting.ts +++ b/packages/designer/src/designer/detecting.ts @@ -1,4 +1,4 @@ -import { obx } from '@ali/lowcode-editor-core'; +import { makeObservable, obx } from '@ali/lowcode-editor-core'; import { Node, DocumentModel } from '../document'; export class Detecting { @@ -19,6 +19,10 @@ export class Detecting { @obx.ref private _current: Node | null = null; + constructor() { + makeObservable(this); + } + get current() { return this._current; } diff --git a/packages/designer/src/designer/drag-ghost/index.tsx b/packages/designer/src/designer/drag-ghost/index.tsx index 195d3cacd..f881f9bd8 100644 --- a/packages/designer/src/designer/drag-ghost/index.tsx +++ b/packages/designer/src/designer/drag-ghost/index.tsx @@ -1,5 +1,5 @@ import { Component } from 'react'; -import { observer, obx, Title } from '@ali/lowcode-editor-core'; +import { observer, obx, Title, makeObservable } from '@ali/lowcode-editor-core'; import { Designer } from '../designer'; import { DragObject, isDragNodeObject, isDragNodeDataObject } from '../dragon'; import { isSimulatorHost } from '../../simulator'; @@ -23,6 +23,7 @@ export default class DragGhost extends Component<{ designer: Designer }> { constructor(props: any) { super(props); + makeObservable(this); this.dispose = [ this.dragon.onDragstart(e => { if (e.originalEvent.type.substr(0, 4) === 'drag') { @@ -52,10 +53,6 @@ export default class DragGhost extends Component<{ designer: Designer }> { ]; } - shouldComponentUpdate() { - return false; - } - componentWillUnmount() { if (this.dispose) { this.dispose.forEach(off => off()); diff --git a/packages/designer/src/designer/dragon.ts b/packages/designer/src/designer/dragon.ts index 5bf5e20fb..8e2e2a8da 100644 --- a/packages/designer/src/designer/dragon.ts +++ b/packages/designer/src/designer/dragon.ts @@ -1,5 +1,5 @@ import { EventEmitter } from 'events'; -import { obx } from '@ali/lowcode-editor-core'; +import { obx, makeObservable } from '@ali/lowcode-editor-core'; import { NodeSchema } from '@ali/lowcode-types'; import { setNativeSelection, cursor } from '@ali/lowcode-utils'; import { DropLocation } from './location'; @@ -213,7 +213,9 @@ export class Dragon { private emitter = new EventEmitter(); - constructor(readonly designer: Designer) {} + constructor(readonly designer: Designer) { + makeObservable(this); + } /** * Quick listen a shell(container element) drag behavior diff --git a/packages/designer/src/designer/offset-observer.ts b/packages/designer/src/designer/offset-observer.ts index 85dfca9db..09fdde26b 100644 --- a/packages/designer/src/designer/offset-observer.ts +++ b/packages/designer/src/designer/offset-observer.ts @@ -1,4 +1,4 @@ -import { obx, computed } from '@ali/lowcode-editor-core'; +import { obx, computed, makeObservable } from '@ali/lowcode-editor-core'; import { uniqueId } from '@ali/lowcode-utils'; import { INodeSelector, IViewport } from '../simulator'; import { isRootNode, Node } from '../document'; @@ -106,8 +106,9 @@ export class OffsetObserver { const doc = node.document; const host = doc.simulator!; const focusNode = doc.focusNode; - this.isRoot = node.contains(focusNode); + this.isRoot = node.contains(focusNode!); this.viewport = host.viewport; + makeObservable(this); if (this.isRoot) { this.hasOffset = true; return; diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index 819e068d1..02729a317 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -2,7 +2,7 @@ import { TitleContent, isDynamicSetter, SetterType, DynamicSetter, FieldExtraPro import { Transducer } from './utils'; import { SettingPropEntry } from './setting-prop-entry'; import { SettingEntry } from './setting-entry'; -import { computed, obx } from '@ali/lowcode-editor-core'; +import { computed, obx, makeObservable, action } from '@ali/lowcode-editor-core'; import { cloneDeep } from '@ali/lowcode-utils'; import { ISetValueOptions } from '../../types'; @@ -63,7 +63,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry { constructor(parent: SettingEntry, config: FieldConfig, settingFieldCollector?: (name: string | number, field: SettingField) => void) { super(parent, config.name, config.type); - + makeObservable(this); const { title, items, setter, extraProps, ...rest } = config; this.parent = parent; this._config = config; @@ -141,6 +141,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry { private hotValue: any; + @action setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: ISetValueOptions) { if (isHotValue) { this.setHotValue(val, extraOptions); @@ -162,6 +163,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry { } /* istanbul ignore next */ + @action setMiniAppDataSourceValue(data: any, options?: any) { this.hotValue = data; const v = this.transducer.toNative(data); @@ -174,6 +176,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry { this.valueChange(); } + @action setHotValue(data: any, options?: ISetValueOptions) { this.hotValue = data; const value = this.transducer.toNative(data); diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index 5a8a369d1..43e4a882a 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -1,4 +1,4 @@ -import { obx, computed } from '@ali/lowcode-editor-core'; +import { obx, computed, makeObservable, runInAction } from '@ali/lowcode-editor-core'; import { IEditor, isJSExpression } from '@ali/lowcode-types'; import { uniqueId } from '@ali/lowcode-utils'; import { SettingEntry } from './setting-entry'; @@ -53,6 +53,7 @@ export class SettingPropEntry implements SettingEntry { extraProps: any = {}; constructor(readonly parent: SettingEntry, name: string | number, type?: 'field' | 'group') { + makeObservable(this); if (type == null) { const c = typeof name === 'string' ? name.substr(0, 1) : ''; if (c === '#') { @@ -120,34 +121,36 @@ export class SettingPropEntry implements SettingEntry { */ /* istanbul ignore next */ @computed get valueState(): number { - if (this.type !== 'field') { - const { getValue } = this.extraProps; - return getValue ? (getValue(this, undefined) === undefined ? 0 : 1) : 0; - } - const propName = this.path.join('.'); - const first = this.nodes[0].getProp(propName)!; - let l = this.nodes.length; - let state = 2; - while (l-- > 1) { - const next = this.nodes[l].getProp(propName, false); - const s = first.compare(next); - if (s > 1) { - return -1; + return runInAction(() => { + if (this.type !== 'field') { + const { getValue } = this.extraProps; + return getValue ? (getValue(this, undefined) === undefined ? 0 : 1) : 0; } - if (s === 1) { - state = 1; + const propName = this.path.join('.'); + const first = this.nodes[0].getProp(propName)!; + let l = this.nodes.length; + let state = 2; + while (--l > 0) { + const next = this.nodes[l].getProp(propName, false); + const s = first.compare(next); + if (s > 1) { + return -1; + } + if (s === 1) { + state = 1; + } } - } - if (state === 2 && first.isUnset()) { - return 0; - } - return state; + if (state === 2 && first.isUnset()) { + return 0; + } + return state; + }); } /** * 获取当前属性值 */ - @computed getValue(): any { + getValue(): any { let val: any; if (this.type === 'field') { val = this.parent.getPropValue(this.name); diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 1417a0c58..d7eca26ae 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -1,4 +1,4 @@ -import { computed, obx } from '@ali/lowcode-editor-core'; +import { computed, makeObservable, obx, action } from '@ali/lowcode-editor-core'; import { NodeData, isJSExpression, isDOMText, NodeSchema, isNodeSchema, RootSchema, PageSchema } from '@ali/lowcode-types'; import { EventEmitter } from 'events'; import { Project } from '../project'; @@ -61,7 +61,7 @@ export class DocumentModel { readonly designer: Designer; - @obx.val private nodes = new Set(); + @obx.shallow private nodes = new Set(); private seqId = 0; @@ -117,13 +117,7 @@ export class DocumentModel { private inited = false; constructor(project: Project, schema?: RootSchema) { - /* - // TODO - // use special purge process - autorun(() => { - console.info(this.willPurgeSpace); - }, true); - */ + makeObservable(this); this.project = project; this.designer = this.project?.designer; this.emitter = new EventEmitter(); @@ -161,7 +155,7 @@ export class DocumentModel { this.inited = true; } - @obx.val private willPurgeSpace: Node[] = []; + @obx.shallow private willPurgeSpace: Node[] = []; get modalNode() { return this._modalNode; @@ -182,7 +176,7 @@ export class DocumentModel { } } - @computed isBlank() { + isBlank() { return this._blank && !this.isModified(); } @@ -213,7 +207,7 @@ export class DocumentModel { return node ? !node.isPurged : false; } - @obx.val private activeNodes?: Node[]; + @obx.shallow private activeNodes?: Node[]; /** * 根据 schema 创建一个节点 @@ -362,6 +356,7 @@ export class DocumentModel { return this.rootNode?.schema as any; } + @action import(schema: RootSchema, checkId = false) { const drillDownNodeId = this._drillDownNode?.id; // TODO: 暂时用饱和式删除,原因是 Slot 节点并不是树节点,无法正常递归删除 diff --git a/packages/designer/src/document/document-view.tsx b/packages/designer/src/document/document-view.tsx index e5018f486..2634afcc9 100644 --- a/packages/designer/src/document/document-view.tsx +++ b/packages/designer/src/document/document-view.tsx @@ -6,10 +6,6 @@ import { BuiltinSimulatorHostView } from '../builtin-simulator'; @observer export class DocumentView extends Component<{ document: DocumentModel }> { - shouldComponentUpdate() { - return false; - } - render() { const { document } = this.props; const { simulatorProps } = document; diff --git a/packages/designer/src/document/history.ts b/packages/designer/src/document/history.ts index 7688c2a1a..401075a63 100644 --- a/packages/designer/src/document/history.ts +++ b/packages/designer/src/document/history.ts @@ -31,20 +31,16 @@ export class History { private emitter = new EventEmitter(); - private obx: Reaction; - - private justWokeup = false; + private asleep = false; constructor(logger: () => any, private redoer: (data: NodeSchema) => void, private timeGap: number = 1000) { this.session = new Session(0, null, this.timeGap); this.records = [this.session]; - this.obx = autorun(() => { + autorun(() => { + if (this.asleep) return; const data = logger(); - if (this.justWokeup) { - this.justWokeup = false; - return; - } + untracked(() => { const log = currentSerialization.serialize(data); if (this.session.cursor === 0 && this.session.isActive()) { @@ -68,7 +64,7 @@ export class History { } } }); - }, true).$obx; + }); } get hotData() { @@ -79,6 +75,14 @@ export class History { return this.point !== this.session.cursor; } + private sleep() { + this.asleep = true; + } + + private wakeup() { + this.asleep = false; + } + go(cursor: number) { this.session.end(); @@ -96,7 +100,7 @@ export class History { const session = this.records[cursor]; const hotData = session.data; - this.obx.sleep(); + this.sleep(); try { this.redoer(currentSerialization.unserialize(hotData)); this.emitter.emit('cursor', hotData); @@ -104,8 +108,7 @@ export class History { // } - this.justWokeup = true; - this.obx.wakeup(); + this.wakeup(); this.session = session; this.emitter.emit('statechange', this.getState()); diff --git a/packages/designer/src/document/node/exclusive-group.ts b/packages/designer/src/document/node/exclusive-group.ts index 87d2bc506..2c6a80734 100644 --- a/packages/designer/src/document/node/exclusive-group.ts +++ b/packages/designer/src/document/node/exclusive-group.ts @@ -1,4 +1,4 @@ -import { obx, computed } from '@ali/lowcode-editor-core'; +import { obx, computed, makeObservable } from '@ali/lowcode-editor-core'; import { uniqueId } from '@ali/lowcode-utils'; import { TitleContent } from '@ali/lowcode-types'; import { Node } from './node'; @@ -11,7 +11,7 @@ export class ExclusiveGroup { readonly id = uniqueId('exclusive'); - @obx.val readonly children: Node[] = []; + @obx.shallow readonly children: Node[] = []; @obx private visibleIndex = 0; @@ -75,6 +75,7 @@ export class ExclusiveGroup { readonly title: TitleContent; constructor(readonly name: string, title?: TitleContent) { + makeObservable(this); this.title = title || { type: 'i18n', intl: intl('Condition Group'), diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index 221672d3b..bc37cfd20 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -1,4 +1,4 @@ -import { obx, computed, globalContext } from '@ali/lowcode-editor-core'; +import { obx, computed, globalContext, makeObservable } from '@ali/lowcode-editor-core'; import { Node, ParentalNode } from './node'; import { TransformStage } from './transform-stage'; import { NodeData, isNodeSchema } from '@ali/lowcode-types'; @@ -8,11 +8,12 @@ import { foreachReverse } from '../../utils/tree'; import { NodeRemoveOptions } from '../../types'; export class NodeChildren { - @obx.val private children: Node[]; + @obx.shallow private children: Node[]; private emitter = new EventEmitter(); constructor(readonly owner: ParentalNode, data: NodeData | NodeData[], options: any = {}) { + makeObservable(this); this.children = (Array.isArray(data) ? data : [data]).map(child => { return this.owner.document.createNode(child, options.checkId); }); @@ -83,11 +84,11 @@ export class NodeChildren { /** * 是否空 */ - @computed isEmpty() { + isEmpty() { return this.size < 1; } - @computed notEmpty() { + notEmpty() { return this.size > 0; } @@ -387,7 +388,7 @@ export class NodeChildren { } if (owner.parent && !owner.parent.isRoot()) { - this.reportModified(node, owner.parent, { ...options, propagated: true, }); + this.reportModified(node, owner.parent, { ...options, propagated: true }); } } } diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 62cb3bf84..dd43cabc4 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -1,6 +1,6 @@ import { ReactElement } from 'react'; import { EventEmitter } from 'events'; -import { obx, computed, autorun } from '@ali/lowcode-editor-core'; +import { obx, computed, autorun, makeObservable, runInAction, getObserverTree } from '@ali/lowcode-editor-core'; import { isDOMText, isJSExpression, @@ -160,6 +160,7 @@ export class Node { isInited = false; constructor(readonly document: DocumentModel, nodeSchema: Schema, options: any = {}) { + makeObservable(this); const { componentName, id, children, props, ...extras } = nodeSchema; this.id = document.nextId(id); this.componentName = componentName; @@ -208,7 +209,7 @@ export class Node { this.autoruns = autoruns.map((item) => { return autorun(() => { item.autorun(this.props.get(item.name, true) as any); - }, true); + }); }); } @@ -382,7 +383,7 @@ export class Node { * 获取当前节点的锁定状态 */ get isLocked(): boolean { - return !!this.getExtraProp('isLocked', false)?.getValue(); + return !!this.getExtraProp('isLocked')?.getValue(); } /** @@ -417,9 +418,9 @@ export class Node { return this.props.export(TransformStage.Serilize).props || null; } - @obx.val _slots: Node[] = []; + @obx.shallow _slots: Node[] = []; - @computed hasSlots() { + hasSlots() { return this._slots.length > 0; } @@ -465,7 +466,7 @@ export class Node { } /* istanbul ignore next */ - @computed isConditionalVisible(): boolean | undefined { + isConditionalVisible(): boolean | undefined { return this._conditionGroup?.isVisible(this); } @@ -474,7 +475,7 @@ export class Node { this._conditionGroup?.setVisible(this); } - @computed hasCondition() { + hasCondition() { const v = this.getExtraProp('condition', false)?.getValue(); return v != null && v !== '' && v !== true; } @@ -483,7 +484,7 @@ export class Node { * has loop when 1. loop is validArray with length > 1 ; OR 2. loop is variable object * @return boolean, has loop config or not */ - @computed hasLoop() { + hasLoop() { const value = this.getExtraProp('loop', false)?.getValue(); if (value === undefined || value === null) { return false; @@ -550,12 +551,12 @@ export class Node { }; } - getProp(path: string, stash = true): Prop | null { - return this.props.query(path, stash as any) || null; + getProp(path: string, createIfNone = true): Prop | null { + return this.props.query(path, createIfNone) || null; } - getExtraProp(key: string, stash = true): Prop | null { - return this.props.get(getConvertedExtraKey(key), stash) || null; + getExtraProp(key: string, createIfNone = true): Prop | null { + return this.props.get(getConvertedExtraKey(key), createIfNone) || null; } setExtraProp(key: string, value: CompositeValue) { @@ -647,7 +648,7 @@ export class Node { } set schema(data: Schema) { - this.import(data); + runInAction(() => this.import(data)); } import(data: Schema, checkId = false) { @@ -865,9 +866,6 @@ export class Node { return this.componentName; } - /** - * @deprecated - */ insert(node: Node, ref?: Node, useMutator = true) { this.insertAfter(node, ref, useMutator); } @@ -918,7 +916,7 @@ export class Node { this.children?.mergeChildren(remover, adder, sorter); } - @obx.val status: NodeStatus = { + @obx.shallow status: NodeStatus = { inPlaceEditing: false, locking: false, pseudo: false, diff --git a/packages/designer/src/document/node/props/prop-stash.ts b/packages/designer/src/document/node/props/prop-stash.ts index ca2fc4507..4c0da5be8 100644 --- a/packages/designer/src/document/node/props/prop-stash.ts +++ b/packages/designer/src/document/node/props/prop-stash.ts @@ -1,4 +1,4 @@ -import { obx, autorun, untracked, computed } from '@ali/lowcode-editor-core'; +import { obx, autorun, untracked, computed, makeObservable, action } from '@ali/lowcode-editor-core'; import { Prop, IPropParent, UNSET } from './prop'; import { Props } from './props'; import { Node } from '../node'; @@ -7,7 +7,7 @@ export type PendingItem = Prop[]; export class PropStash implements IPropParent { readonly isPropStash = true; - @obx.val private space: Set = new Set(); + @obx.shallow private space: Set = new Set(); @computed private get maps(): Map { const maps = new Map(); @@ -24,6 +24,7 @@ export class PropStash implements IPropParent { readonly owner: Node; constructor(readonly props: Props, write: (item: Prop) => void) { + makeObservable(this); this.owner = props.owner; this.willPurge = autorun(() => { if (this.space.size < 1) { @@ -46,6 +47,7 @@ export class PropStash implements IPropParent { }); } + @action get(key: string | number): Prop { let prop = this.maps.get(key); if (!prop) { @@ -55,16 +57,19 @@ export class PropStash implements IPropParent { return prop; } + @action delete(prop: Prop) { this.space.delete(prop); prop.purge(); } + @action clear() { this.space.forEach(item => item.purge()); this.space.clear(); } + @action purge() { this.willPurge(); this.space.clear(); diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 4a654a34a..3ef16c34e 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -1,12 +1,12 @@ -import { untracked, computed, obx, engineConfig } from '@ali/lowcode-editor-core'; +import { untracked, computed, obx, engineConfig, action, makeObservable, mobx } from '@ali/lowcode-editor-core'; import { CompositeValue, FieldConfig, isJSExpression, isJSSlot, JSSlot, SlotSchema } from '@ali/lowcode-types'; import { uniqueId, isPlainObject, hasOwnProperty, compatStage } from '@ali/lowcode-utils'; -import { PropStash } from './prop-stash'; import { valueToSource } from './value-to-source'; import { Props } from './props'; import { SlotNode, Node } from '../node'; import { TransformStage } from '../transform-stage'; +const { set: mobxSet, isObservableArray } = mobx; export const UNSET = Symbol.for('unset'); export type UNSET = typeof UNSET; @@ -24,8 +24,6 @@ export class Prop implements IPropParent { readonly owner: Node; - private stash: PropStash | undefined; - /** * 键值 */ @@ -47,6 +45,7 @@ export class Prop implements IPropParent { spread = false, options = {}, ) { + makeObservable(this); this.owner = parent.owner; this.props = parent.props; this.key = key; @@ -59,6 +58,7 @@ export class Prop implements IPropParent { } // TODO: 先用调用方式触发子 prop 的初始化,后续须重构 + @action private setupItems() { return this.items; } @@ -66,6 +66,7 @@ export class Prop implements IPropParent { /** * @see SettingTarget */ + @action getPropValue(propName: string | number): any { return this.get(propName)!.getValue(); } @@ -73,6 +74,7 @@ export class Prop implements IPropParent { /** * @see SettingTarget */ + @action setPropValue(propName: string | number, value: any): void { this.set(propName, value); } @@ -80,6 +82,7 @@ export class Prop implements IPropParent { /** * @see SettingTarget */ + @action clearPropValue(propName: string | number): void { this.get(propName, false)?.unset(); } @@ -95,7 +98,7 @@ export class Prop implements IPropParent { return this._type; } - @obx.ref private _value: any = UNSET; + @obx private _value: any = UNSET; /** * 属性值 @@ -213,7 +216,7 @@ export class Prop implements IPropParent { this._code = code; } - @computed getAsString(): string { + getAsString(): string { if (this.type === 'literal') { return this._value ? String(this._value) : ''; } @@ -223,6 +226,7 @@ export class Prop implements IPropParent { /** * set value, val should be JSON Object */ + @action setValue(val: CompositeValue) { if (val === this._value) return; const editor = this.owner.document?.designer.editor; @@ -267,10 +271,11 @@ export class Prop implements IPropParent { } } - @computed getValue(): CompositeValue { + getValue(): CompositeValue { return this.export(TransformStage.Serilize); } + @action private dispose() { const items = untracked(() => this._items); if (items) { @@ -278,9 +283,6 @@ export class Prop implements IPropParent { } this._items = null; this._maps = null; - if (this.stash) { - this.stash.clear(); - } if (this._type !== 'slot' && this._slotNode) { this._slotNode.remove(); this._slotNode = undefined; @@ -293,6 +295,7 @@ export class Prop implements IPropParent { return this._slotNode; } + @action setAsSlot(data: JSSlot) { this._type = 'slot'; const slotSchema: SlotSchema = { @@ -315,6 +318,7 @@ export class Prop implements IPropParent { /** * 取消设置值 */ + @action unset() { this._type = 'unset'; } @@ -322,6 +326,7 @@ export class Prop implements IPropParent { /** * 是否未设置值 */ + @action isUnset() { return this._type === 'unset'; } @@ -352,9 +357,9 @@ export class Prop implements IPropParent { return this.code === other.code ? 0 : 2; } - @obx.val private _items: Prop[] | null = null; + @obx.shallow private _items: Prop[] | null = null; - @obx.val private _maps: Map | null = null; + @obx.shallow private _maps: Map | null = null; get path(): string[] { return (this.parent.path || []).concat(this.key as string); @@ -401,11 +406,12 @@ export class Prop implements IPropParent { /** * 获取某个属性 - * @param stash 如果不存在,临时获取一个待写入 + * @param createIfNone 当没有的时候,是否创建一个 */ - get(path: string | number, stash = true): Prop | null { + @action + get(path: string | number, createIfNone = true): Prop | null { const type = this._type; - if (type !== 'map' && type !== 'list' && type !== 'unset' && !stash) { + if (type !== 'map' && type !== 'list' && type !== 'unset' && !createIfNone) { return null; } @@ -434,20 +440,12 @@ export class Prop implements IPropParent { } if (prop) { - return nest ? prop.get(nest, stash) : prop; + return nest ? prop.get(nest, createIfNone) : prop; } - if (stash) { - if (!this.stash) { - this.stash = new PropStash(this.props, (item) => { - // item take effect - if (item.key) { - this.set(item.key, item, true); - } - item.parent = this; - }); - } - prop = this.stash.get(entry); + if (createIfNone) { + prop = new Prop(this, UNSET, entry); + this.set(entry, prop, true); if (nest) { return prop.get(nest, true); } @@ -461,6 +459,7 @@ export class Prop implements IPropParent { /** * 从父级移除本身 */ + @action remove() { this.parent.delete(this); } @@ -468,6 +467,7 @@ export class Prop implements IPropParent { /** * 删除项 */ + @action delete(prop: Prop): void { if (this.items) { const i = this.items.indexOf(prop); @@ -484,6 +484,7 @@ export class Prop implements IPropParent { /** * 删除 key */ + @action deleteKey(key: string): void { if (this.maps) { const prop = this.maps.get(key); @@ -505,6 +506,7 @@ export class Prop implements IPropParent { * * @param force 强制 */ + @action add(value: CompositeValue, force = false): Prop | null { const type = this._type; if (type !== 'list' && type !== 'unset' && !force) { @@ -523,6 +525,7 @@ export class Prop implements IPropParent { * * @param force 强制 */ + @action set(key: string | number, value: CompositeValue | Prop, force = false) { const type = this._type; if (type !== 'map' && type !== 'list' && type !== 'unset' && !force) { @@ -543,7 +546,11 @@ export class Prop implements IPropParent { if (!isValidArrayIndex(key)) { return null; } - items[key] = prop; + if (isObservableArray(items)) { + mobxSet(items, key, prop); + } else { + items[key] = prop; + } } else if (this.maps) { const { maps } = this; const orig = maps.get(key); @@ -584,14 +591,12 @@ export class Prop implements IPropParent { /** * 回收销毁 */ + @action purge() { if (this.purged) { return; } this.purged = true; - if (this.stash) { - this.stash.purge(); - } if (this._items) { this._items.forEach((item) => item.purge()); } @@ -627,6 +632,7 @@ export class Prop implements IPropParent { /** * 遍历 */ + @action forEach(fn: (item: Prop, key: number | string | undefined) => void): void { const { items } = this; if (!items) { @@ -641,6 +647,7 @@ export class Prop implements IPropParent { /** * 遍历 */ + @action map(fn: (item: Prop, key: number | string | undefined) => T): T[] | null { const { items } = this; if (!items) { diff --git a/packages/designer/src/document/node/props/props.ts b/packages/designer/src/document/node/props/props.ts index eefe3ad01..bdf7ab470 100644 --- a/packages/designer/src/document/node/props/props.ts +++ b/packages/designer/src/document/node/props/props.ts @@ -1,7 +1,6 @@ -import { computed, obx } from '@ali/lowcode-editor-core'; +import { computed, makeObservable, obx, action } from '@ali/lowcode-editor-core'; import { PropsMap, PropsList, CompositeValue } from '@ali/lowcode-types'; import { uniqueId, compatStage } from '@ali/lowcode-utils'; -import { PropStash } from './prop-stash'; import { Prop, IPropParent, UNSET } from './prop'; import { Node } from '../node'; import { TransformStage } from '../transform-stage'; @@ -23,7 +22,7 @@ export function getOriginalExtraKey(key: string): string { export class Props implements IPropParent { readonly id = uniqueId('props'); - @obx.val private items: Prop[] = []; + @obx.shallow private items: Prop[] = []; @computed private get maps(): Map { const maps = new Map(); @@ -45,8 +44,6 @@ export class Props implements IPropParent { readonly owner: Node; - private stash: PropStash; - /** * 元素个数 */ @@ -57,11 +54,8 @@ export class Props implements IPropParent { @obx type: 'map' | 'list' = 'map'; constructor(owner: Node, value?: PropsMap | PropsList | null, extras?: object) { + makeObservable(this); this.owner = owner; - this.stash = new PropStash(this, prop => { - this.items.push(prop); - prop.parent = this; - }); if (Array.isArray(value)) { this.type = 'list'; this.items = value.map(item => new Prop(this, item.value, item.name, item.spread)); @@ -75,8 +69,8 @@ export class Props implements IPropParent { } } + @action import(value?: PropsMap | PropsList | null, extras?: object) { - this.stash.clear(); const originItems = this.items; if (Array.isArray(value)) { this.type = 'list'; @@ -96,6 +90,7 @@ export class Props implements IPropParent { originItems.forEach(item => item.purge()); } + @action merge(value: PropsMap, extras?: PropsMap) { Object.keys(value).forEach(key => { this.query(key, true)!.setValue(value[key]); @@ -119,9 +114,6 @@ export class Props implements IPropParent { props = []; this.items.forEach(item => { let value = item.export(stage); - if (value === UNSET) { - value = undefined; - } let name = item.key as string; if (name && typeof name === 'string' && name.startsWith(EXTRA_KEY_PREFIX)) { name = getOriginalExtraKey(name); @@ -142,9 +134,6 @@ export class Props implements IPropParent { return; } let value = item.export(stage); - if (value === UNSET) { - value = undefined; - } allProps[name] = value; }); // compatible vision @@ -187,53 +176,19 @@ export class Props implements IPropParent { /** * 根据 path 路径查询属性 * - * @param stash 如果没有则临时生成一个 + * @param createIfNone 当没有的时候,是否创建一个 */ - query(path: string, stash = true): Prop | null { - return this.get(path, stash); - // todo: future support list search - // let matchedLength = 0; - // let firstMatched = null; - // if (this.items) { - // // target: a.b.c - // // trys: a.b.c, a.b, a - // let i = this.items.length; - // while (i-- > 0) { - // const expr = this.items[i]; - // if (!expr.key) { - // continue; - // } - // const name = String(expr.key); - // if (name === path) { - // // completely match - // return expr; - // } - - // // fisrt match - // const l = name.length; - // if (path.slice(0, l + 1) === `${name}.`) { - // matchedLength = l; - // firstMatched = expr; - // } - // } - // } - - // let ret = null; - // if (firstMatched) { - // ret = firstMatched.get(path.slice(matchedLength + 1), true); - // } - // if (!ret && stash) { - // return this.stash.get(path); - // } - - // return ret; + @action + query(path: string, createIfNone = true): Prop | null { + return this.get(path, createIfNone); } /** * 获取某个属性, 如果不存在,临时获取一个待写入 - * @param stash 强制 + * @param createIfNone 当没有的时候,是否创建一个 */ - get(path: string, stash = false): Prop | null { + @action + get(path: string, createIfNone = false): Prop | null { let entry = path; let nest = ''; const i = path.indexOf('.'); @@ -244,10 +199,14 @@ export class Props implements IPropParent { } } - const prop = this.maps.get(entry) || (stash && this.stash.get(entry)) || null; + let prop = this.maps.get(entry); + if (!prop && createIfNone) { + prop = new Prop(this, UNSET, entry); + this.items.push(prop); + } if (prop) { - return nest ? prop.get(nest, stash) : prop; + return nest ? prop.get(nest, createIfNone) : prop; } return null; @@ -256,6 +215,7 @@ export class Props implements IPropParent { /** * 删除项 */ + @action delete(prop: Prop): void { const i = this.items.indexOf(prop); if (i > -1) { @@ -267,6 +227,7 @@ export class Props implements IPropParent { /** * 删除 key */ + @action deleteKey(key: string): void { this.items = this.items.filter(item => { if (item.key === key) { @@ -280,6 +241,7 @@ export class Props implements IPropParent { /** * 添加值 */ + @action add(value: CompositeValue | null, key?: string | number, spread = false, options: any = {}): Prop { const prop = new Prop(this, value, key, spread, options); this.items.push(prop); @@ -319,6 +281,7 @@ export class Props implements IPropParent { /** * 遍历 */ + @action forEach(fn: (item: Prop, key: number | string | undefined) => void): void { this.items.forEach(item => { return fn(item, item.key); @@ -328,12 +291,14 @@ export class Props implements IPropParent { /** * 遍历 */ + @action map(fn: (item: Prop, key: number | string | undefined) => T): T[] | null { return this.items.map(item => { return fn(item, item.key); }); } + @action filter(fn: (item: Prop, key: number | string | undefined) => boolean) { return this.items.filter(item => { return fn(item, item.key); @@ -345,22 +310,28 @@ export class Props implements IPropParent { /** * 回收销毁 */ + @action purge() { if (this.purged) { return; } this.purged = true; - this.stash.purge(); this.items.forEach(item => item.purge()); } - getProp(path: string, stash = true): Prop | null { - return this.query(path, stash as any) || null; + /** + * 获取某个属性, 如果不存在,临时获取一个待写入 + * @param createIfNone 当没有的时候,是否创建一个 + */ + @action + getProp(path: string, createIfNone = true): Prop | null { + return this.query(path, createIfNone) || null; } /** * 获取单个属性值 */ + @action getPropValue(path: string): any { return this.getProp(path, false)?.value; } @@ -368,6 +339,7 @@ export class Props implements IPropParent { /** * 设置单个属性值 */ + @action setPropValue(path: string, value: any) { this.getProp(path, true)!.setValue(value); } @@ -383,6 +355,7 @@ export class Props implements IPropParent { * @deprecated * 获取 props 对应的 node */ + @action toData() { return this.export()?.props; } diff --git a/packages/designer/src/document/selection.ts b/packages/designer/src/document/selection.ts index 3a1a416f8..0a74d3682 100644 --- a/packages/designer/src/document/selection.ts +++ b/packages/designer/src/document/selection.ts @@ -1,14 +1,16 @@ import { EventEmitter } from 'events'; -import { obx } from '@ali/lowcode-editor-core'; +import { obx, makeObservable } from '@ali/lowcode-editor-core'; import { Node, comparePosition, PositionNO } from './node/node'; import { DocumentModel } from './document-model'; export class Selection { private emitter = new EventEmitter(); - @obx.val private _selected: string[] = []; + @obx.shallow private _selected: string[] = []; - constructor(readonly doc: DocumentModel) {} + constructor(readonly doc: DocumentModel) { + makeObservable(this); + } /** * 选中的节点 id diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index bce7876b4..b30de9901 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -1,5 +1,5 @@ import { EventEmitter } from 'events'; -import { obx, computed } from '@ali/lowcode-editor-core'; +import { obx, computed, makeObservable, action } from '@ali/lowcode-editor-core'; import { Designer } from '../designer'; import { DocumentModel, isDocumentModel, isPageSchema } from '../document'; import { ProjectSchema, RootSchema } from '@ali/lowcode-types'; @@ -8,7 +8,7 @@ import { ISimulatorHost } from '../simulator'; export class Project { private emitter = new EventEmitter(); - @obx.val readonly documents: DocumentModel[] = []; + @obx.shallow readonly documents: DocumentModel[] = []; private data: ProjectSchema = { version: '1.0.0', componentsMap: [], componentsTree: [], i18n: {} }; @@ -24,6 +24,7 @@ export class Project { // TODO: 考虑项目级别 History constructor(readonly designer: Designer, schema?: ProjectSchema) { + makeObservable(this); this.load(schema); } @@ -76,6 +77,7 @@ export class Project { * * @param autoOpen true 自动打开文档 string 指定打开的文件 */ + @action load(schema?: ProjectSchema, autoOpen?: boolean | string) { this.unload(); // load new document diff --git a/packages/designer/tests/builtin-simulator/host.test.ts b/packages/designer/tests/builtin-simulator/host.test.ts index 414f6f947..959cca687 100644 --- a/packages/designer/tests/builtin-simulator/host.test.ts +++ b/packages/designer/tests/builtin-simulator/host.test.ts @@ -105,7 +105,7 @@ describe('Host 测试', () => { type: AssetType.CSSText, content: '.theme {font-size: 50px;}', }); - expect(host.componentsMap).toBe(designer.componentsMap); + expect(host.componentsMap).toEqual(designer.componentsMap); expect(host.requestHandlersMap).toEqual({}); host.set('renderEnv', 'vue'); diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 88d6701f8..1b55890f1 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -85,7 +85,7 @@ describe('Prop 类测试', () => { strProp.unset(); strProp.add(2, true); - strProp.set(1); + strProp.set(0); expect(numProp.set()).toBeNull(); expect(numProp.has()).toBeFalsy(); @@ -391,7 +391,7 @@ describe('Prop 类测试', () => { prop.unset(); prop.set(0, true); expect(prop.set('x', 'invalid')).toBeNull(); - expect(prop.get(0).getValue()).toBeTruthy(); + expect(prop.get(0).getValue()).toBeUndefined(); }); it('export', () => { diff --git a/packages/designer/tests/main/meta/component-meta.test.ts b/packages/designer/tests/main/meta/component-meta.test.ts index b53a34b3e..528ad244e 100644 --- a/packages/designer/tests/main/meta/component-meta.test.ts +++ b/packages/designer/tests/main/meta/component-meta.test.ts @@ -50,10 +50,9 @@ describe('组件元数据处理', () => { expect(meta.availableActions[2].name).toBe('copy'); removeBuiltinComponentAction('remove'); - // availableActions 有 computed 缓存 - expect(meta.availableActions[0].name).toBe('remove'); - expect(meta.availableActions[1].name).toBe('hide'); - expect(meta.availableActions[2].name).toBe('copy'); + expect(meta.availableActions).toHaveLength(4); + expect(meta.availableActions[0].name).toBe('hide'); + expect(meta.availableActions[1].name).toBe('copy'); addBuiltinComponentAction({ name: 'new', @@ -61,10 +60,9 @@ describe('组件元数据处理', () => { action() {}, }, }); - // availableActions 有 computed 缓存 expect(meta.availableActions).toHaveLength(5); - expect(meta.availableActions[0].name).toBe('remove'); - expect(meta.availableActions[1].name).toBe('hide'); - expect(meta.availableActions[2].name).toBe('copy'); + expect(meta.availableActions[0].name).toBe('hide'); + expect(meta.availableActions[1].name).toBe('copy'); + expect(meta.availableActions[4].name).toBe('new'); }); }); diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index dda569260..afd4a897d 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -16,8 +16,6 @@ "@ali/lowcode-types": "1.0.66", "@ali/lowcode-utils": "1.0.66", "@alifd/next": "^1.19.16", - "@recore/obx": "^1.0.9", - "@recore/obx-react": "^1.0.8", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", @@ -25,7 +23,9 @@ "power-di": "^2.2.4", "react": "^16", "react-dom": "^16.7.0", - "store": "^2.0.12" + "store": "^2.0.12", + "mobx": "^6.3.0", + "mobx-react": "^7.2.0" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index 2c478944c..0a527524f 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -39,7 +39,7 @@ export class Editor extends EventEmitter implements IEditor { /** * Ioc Container */ - @obx.val private context = new Map(); + @obx.shallow private context = new Map(); get locale() { return globalLocale.getLocale(); diff --git a/packages/editor-core/src/intl/index.ts b/packages/editor-core/src/intl/index.ts index e4d6b4e37..91fa28073 100644 --- a/packages/editor-core/src/intl/index.ts +++ b/packages/editor-core/src/intl/index.ts @@ -97,7 +97,8 @@ export function createIntl( getLocale(): string; setLocale(locale: string): void; } { - const data = computed(() => { + // TODO: make reactive + const data = (() => { const locale = globalLocale.getLocale(); if (typeof instance === 'string') { if ((window as any)[instance]) { @@ -110,11 +111,11 @@ export function createIntl( return (instance as any)[locale] || {}; } return {}; - }); + })(); function intl(key: string, params?: object): string { // TODO: tries lost language - const str = data.value[key]; + const str = data[key]; if (str == null) { return `##intl@${key}##`; diff --git a/packages/editor-core/src/utils/obx.ts b/packages/editor-core/src/utils/obx.ts index 627a7e273..f10b67756 100644 --- a/packages/editor-core/src/utils/obx.ts +++ b/packages/editor-core/src/utils/obx.ts @@ -1,5 +1,24 @@ -import { observer } from '@recore/obx-react'; +import { observer } from 'mobx-react'; +import { configure } from 'mobx'; -export * from '@recore/obx'; +configure({ enforceActions: 'never' }); +// 常用的直接导出,其他的以 mobx 命名空间导出 +export { + observable as obx, + observable, + observe, + autorun, + makeObservable, + makeAutoObservable, + reaction, + computed, + action, + runInAction, + untracked, + IReactionDisposer, + IReactionPublic, + IReactionOptions, +} from 'mobx'; +export * as mobx from 'mobx'; export { observer }; diff --git a/packages/editor-skeleton/src/area.ts b/packages/editor-skeleton/src/area.ts index d2de6cecf..c41abe18c 100644 --- a/packages/editor-skeleton/src/area.ts +++ b/packages/editor-skeleton/src/area.ts @@ -1,4 +1,4 @@ -import { obx, computed } from '@ali/lowcode-editor-core'; +import { obx, computed, makeObservable } from '@ali/lowcode-editor-core'; import WidgetContainer from './widget/widget-container'; import { Skeleton } from './skeleton'; import { IWidget } from './widget/widget'; @@ -24,10 +24,11 @@ export default class Area; constructor(readonly skeleton: Skeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent = false) { + makeObservable(this); this.container = skeleton.createContainer(name, handle, exclusive, () => this.visible, defaultSetCurrent); } - @computed isEmpty(): boolean { + isEmpty(): boolean { return this.container.items.length < 1; } diff --git a/packages/editor-skeleton/src/components/array-setter/index.tsx b/packages/editor-skeleton/src/components/array-setter/index.tsx index ad25cdaa2..0e6e732c9 100644 --- a/packages/editor-skeleton/src/components/array-setter/index.tsx +++ b/packages/editor-skeleton/src/components/array-setter/index.tsx @@ -1,6 +1,6 @@ import { Component, Fragment } from 'react'; import { Icon, Button, Message } from '@alifd/next'; -import { Title } from '@ali/lowcode-editor-core'; +import { Title, runInAction } from '@ali/lowcode-editor-core'; import { SetterType, FieldConfig, SetterConfig } from '@ali/lowcode-types'; import { SettingField } from '@ali/lowcode-designer'; import { createSettingFieldView } from '../settings/settings-pane'; @@ -60,9 +60,11 @@ export class ListSetter extends Component { itemsMap, }, () => { // setValue 会触发onItemChange,需要在items被设值之后才能调用 - value && value.map((item, index) => { - items[index].setValue(item); - return item; + runInAction(() => { + value && value.map((item, index) => { + items[index].setValue(item); + return item; + }); }); }); } diff --git a/packages/editor-skeleton/src/components/settings/main.ts b/packages/editor-skeleton/src/components/settings/main.ts index 66e78bc3d..5cd2630a7 100644 --- a/packages/editor-skeleton/src/components/settings/main.ts +++ b/packages/editor-skeleton/src/components/settings/main.ts @@ -1,7 +1,6 @@ import { EventEmitter } from 'events'; import { Node, Designer, Selection, SettingTopEntry } from '@ali/lowcode-designer'; -import { Editor, obx, computed } from '@ali/lowcode-editor-core'; -import { executePendingFn } from '@ali/lowcode-utils'; +import { Editor, obx, computed, makeObservable, action } from '@ali/lowcode-editor-core'; function generateSessionId(nodes: Node[]) { return nodes @@ -34,6 +33,7 @@ export class SettingsMain { private designer?: Designer; constructor(readonly editor: Editor) { + makeObservable(this); this.init(); } @@ -54,6 +54,7 @@ export class SettingsMain { setupSelection(designer.currentSelection); } + @action private setup(nodes: Node[]) { // check nodes change const sessionId = generateSessionId(nodes); diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index c08faf429..dc2afbfc2 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -158,10 +158,6 @@ class SettingFieldView extends Component<{ field: SettingField }> { class SettingGroupView extends Component<{ field: SettingField }> { static contextType = SkeletonContext; - shouldComponentUpdate() { - return false; - } - render() { const { field } = this.props; const { extraProps } = field; @@ -227,12 +223,7 @@ export type SettingsPaneProps = { export class SettingsPane extends Component { static contextType = SkeletonContext; - @obx - private currentStage?: Stage; - - shouldComponentUpdate() { - return false; - } + @obx private currentStage?: Stage; private popupPipe = new PopupPipe(); diff --git a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx index 9e6e4c32a..8237fda86 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import { Tab, Breadcrumb } from '@alifd/next'; -import { Title, observer, Editor, obx, globalContext, engineConfig } from '@ali/lowcode-editor-core'; +import { Title, observer, Editor, obx, globalContext, engineConfig, makeObservable } from '@ali/lowcode-editor-core'; import { Node, isSettingField, SettingField, Designer } from '@ali/lowcode-designer'; import { SettingsMain } from './main'; import { SettingsPane } from './settings-pane'; @@ -16,8 +16,9 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any @obx.ref private _activeKey?: any; - shouldComponentUpdate() { - return false; + constructor(props) { + super(props); + makeObservable(this); } componentDidMount() { @@ -62,8 +63,8 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any ); } - const editor = globalContext.get(Editor); - const designer = editor.get(Designer); + const editor = globalContext.get('editor'); + const designer = editor.get('designer'); const current = designer?.currentSelection?.getNodes()?.[0]; let node: Node | null = settings.first; const focusNode = node.document.focusNode; diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index 33d72ff1c..b420bd545 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -157,10 +157,6 @@ export class DraggableLineView extends Component<{ panel: Panel }> { @observer export class TitledPanelView extends Component<{ panel: Panel; area?: string }> { - shouldComponentUpdate() { - return false; - } - componentDidMount() { this.checkVisible(); } @@ -218,10 +214,6 @@ export class PanelView extends Component<{ hideOperationRow?: boolean; hideDragLine?: boolean; }> { - shouldComponentUpdate() { - return false; - } - componentDidMount() { this.checkVisible(); } @@ -333,10 +325,6 @@ class PanelTitle extends Component<{ panel: Panel; className?: string }> { @observer export class WidgetView extends Component<{ widget: IWidget }> { - shouldComponentUpdate() { - return false; - } - componentDidMount() { this.checkVisible(); this.checkDisabled(); diff --git a/packages/editor-skeleton/src/components/widget-views/panel-operation-row.tsx b/packages/editor-skeleton/src/components/widget-views/panel-operation-row.tsx index 3dc06493b..91728efde 100644 --- a/packages/editor-skeleton/src/components/widget-views/panel-operation-row.tsx +++ b/packages/editor-skeleton/src/components/widget-views/panel-operation-row.tsx @@ -1,11 +1,17 @@ import { Component, Fragment } from 'react'; import { Button, Icon } from '@alifd/next'; +import { action, makeObservable } from '@ali/lowcode-editor-core'; import { IconFix } from '../../icons/fix'; import { IconFloat } from '../../icons/float'; import Panel from '../../widget/panel'; export default class PanelOperationRow extends Component<{ panel: Panel }> { + constructor(props) { + super(props); + makeObservable(this); + } // fix or float + @action setDisplay() { const { panel } = this.props; const current = panel; diff --git a/packages/editor-skeleton/src/layouts/bottom-area.tsx b/packages/editor-skeleton/src/layouts/bottom-area.tsx index d7b634390..f9cb605a6 100644 --- a/packages/editor-skeleton/src/layouts/bottom-area.tsx +++ b/packages/editor-skeleton/src/layouts/bottom-area.tsx @@ -6,10 +6,6 @@ import Panel from '../widget/panel'; @observer export default class BottomArea extends Component<{ area: Area }> { - shouldComponentUpdate() { - return false; - } - render() { const { area } = this.props; if (area.isEmpty()) { diff --git a/packages/editor-skeleton/src/layouts/left-area.tsx b/packages/editor-skeleton/src/layouts/left-area.tsx index 7fb10e81a..829cf114b 100644 --- a/packages/editor-skeleton/src/layouts/left-area.tsx +++ b/packages/editor-skeleton/src/layouts/left-area.tsx @@ -25,7 +25,7 @@ class Contents extends Component<{ area: Area }> { const { area } = this.props; const top: any[] = []; const bottom: any[] = []; - area.container.items.sort((a, b) => { + area.container.items.slice().sort((a, b) => { const index1 = a.config?.index || 0; const index2 = b.config?.index || 0; return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1); diff --git a/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx b/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx index 18dd3c8e9..27d86d466 100644 --- a/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx @@ -4,17 +4,12 @@ import { observer } from '@ali/lowcode-editor-core'; import Area from '../area'; import { PanelConfig } from '../types'; import Panel from '../widget/panel'; -import { Designer } from '@ali/lowcode-designer'; @observer export default class LeftFixedPane extends Component<{ area: Area }> { - shouldComponentUpdate() { - return false; - } - componentDidUpdate() { // FIXME: dirty fix, need deep think - this.props.area.skeleton.editor.get(Designer)?.touchOffsetObserver(); + this.props.area.skeleton.editor.get('designer')?.touchOffsetObserver(); } @@ -42,10 +37,6 @@ export default class LeftFixedPane extends Component<{ area: Area }> { - shouldComponentUpdate() { - return false; - } - render() { const { area } = this.props; return {area.container.items.map((panel) => panel.content)}; diff --git a/packages/editor-skeleton/src/layouts/left-float-pane.tsx b/packages/editor-skeleton/src/layouts/left-float-pane.tsx index cdf0c6868..4c5fd6d5d 100644 --- a/packages/editor-skeleton/src/layouts/left-float-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-float-pane.tsx @@ -6,11 +6,6 @@ import Panel from '../widget/panel'; @observer export default class LeftFloatPane extends Component<{ area: Area }> { - - shouldComponentUpdate() { - return false; - } - private dispose?: () => void; private focusing?: Focusable; @@ -118,10 +113,6 @@ export default class LeftFloatPane extends Component<{ area: Area }> @observer class Contents extends Component<{ area: Area }> { - shouldComponentUpdate() { - return false; - } - render() { const { area } = this.props; return ( diff --git a/packages/editor-skeleton/src/layouts/main-area.tsx b/packages/editor-skeleton/src/layouts/main-area.tsx index edd0d1aff..05fe1cf79 100644 --- a/packages/editor-skeleton/src/layouts/main-area.tsx +++ b/packages/editor-skeleton/src/layouts/main-area.tsx @@ -7,10 +7,6 @@ import Widget from '../widget/widget'; @observer export default class MainArea extends Component<{ area: Area }> { - shouldComponentUpdate() { - return false; - } - render() { const { area } = this.props; return ( diff --git a/packages/editor-skeleton/src/layouts/right-area.tsx b/packages/editor-skeleton/src/layouts/right-area.tsx index 448788dd6..d71e7bb0b 100644 --- a/packages/editor-skeleton/src/layouts/right-area.tsx +++ b/packages/editor-skeleton/src/layouts/right-area.tsx @@ -6,10 +6,6 @@ import Panel from '../widget/panel'; @observer export default class RightArea extends Component<{ area: Area }> { - shouldComponentUpdate() { - return false; - } - render() { const { area } = this.props; return ( diff --git a/packages/editor-skeleton/src/layouts/top-area.tsx b/packages/editor-skeleton/src/layouts/top-area.tsx index db8da436b..250dbc952 100644 --- a/packages/editor-skeleton/src/layouts/top-area.tsx +++ b/packages/editor-skeleton/src/layouts/top-area.tsx @@ -25,7 +25,7 @@ class Contents extends Component<{ area: Area, itemClassName?: string }> { const left: any[] = []; const center: any[] = []; const right: any[] = []; - area.container.items.sort((a, b) => { + area.container.items.slice().sort((a, b) => { const index1 = a.config?.index || 0; const index2 = b.config?.index || 0; return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1); diff --git a/packages/editor-skeleton/src/layouts/workbench.tsx b/packages/editor-skeleton/src/layouts/workbench.tsx index ec9bc965d..74424192d 100644 --- a/packages/editor-skeleton/src/layouts/workbench.tsx +++ b/packages/editor-skeleton/src/layouts/workbench.tsx @@ -22,10 +22,6 @@ export class Workbench extends Component<{ skeleton: Skeleton; config?: EditorCo skeleton.buildFromConfig(config, components); } - shouldComponentUpdate() { - return false; - } - // componentDidCatch(error: any) { // globalContext.get(Editor).emit('editor.skeleton.workbench.error', error); // } diff --git a/packages/editor-skeleton/src/widget/dock.ts b/packages/editor-skeleton/src/widget/dock.ts index f402239e9..4369b07c4 100644 --- a/packages/editor-skeleton/src/widget/dock.ts +++ b/packages/editor-skeleton/src/widget/dock.ts @@ -1,5 +1,5 @@ import { ReactNode, createElement } from 'react'; -import { obx } from '@ali/lowcode-editor-core'; +import { makeObservable, obx } from '@ali/lowcode-editor-core'; import { uniqueId, createContent } from '@ali/lowcode-utils'; import { DockConfig } from '../types'; import { Skeleton } from '../skeleton'; @@ -59,6 +59,7 @@ export default class Dock implements IWidget { } constructor(readonly skeleton: Skeleton, readonly config: DockConfig) { + makeObservable(this); const { props = {}, name } = config; this.name = name; this.align = props.align; diff --git a/packages/editor-skeleton/src/widget/panel-dock.ts b/packages/editor-skeleton/src/widget/panel-dock.ts index 9f58a6c22..59858090f 100644 --- a/packages/editor-skeleton/src/widget/panel-dock.ts +++ b/packages/editor-skeleton/src/widget/panel-dock.ts @@ -1,4 +1,4 @@ -import { obx, computed } from '@ali/lowcode-editor-core'; +import { obx, computed, makeObservable } from '@ali/lowcode-editor-core'; import { uniqueId } from '@ali/lowcode-utils'; import { createElement, ReactNode, ReactInstance } from 'react'; import { Skeleton } from '../skeleton'; @@ -77,6 +77,7 @@ export default class PanelDock implements IWidget { } constructor(readonly skeleton: Skeleton, readonly config: PanelDockConfig) { + makeObservable(this); const { content, contentProps, panelProps, name, props } = config; this.name = name; this.id = uniqueId(`dock:${name}$`); diff --git a/packages/editor-skeleton/src/widget/panel.ts b/packages/editor-skeleton/src/widget/panel.ts index 8ecacc43e..b9a4273c6 100644 --- a/packages/editor-skeleton/src/widget/panel.ts +++ b/packages/editor-skeleton/src/widget/panel.ts @@ -1,6 +1,6 @@ import { EventEmitter } from 'events'; import { createElement, ReactNode } from 'react'; -import { obx, computed } from '@ali/lowcode-editor-core'; +import { obx, computed, makeObservable } from '@ali/lowcode-editor-core'; import { uniqueId, createContent } from '@ali/lowcode-utils'; import { TitleContent } from '@ali/lowcode-types'; import WidgetContainer from './widget-container'; @@ -24,7 +24,7 @@ export default class Panel implements IWidget { private emitter = new EventEmitter(); - get actived(): boolean { + @computed get actived(): boolean { return this._actived; } @@ -81,6 +81,7 @@ export default class Panel implements IWidget { private parent?: WidgetContainer; constructor(readonly skeleton: Skeleton, readonly config: PanelConfig) { + makeObservable(this); const { name, content, props = {} } = config; const { hideTitleBar, title, icon, description, help } = props; this.name = name; @@ -160,13 +161,13 @@ export default class Panel implements IWidget { return; } if (flag) { - this._actived = true; - this.parent?.active(this); if (this.parent.name === 'leftFloatArea') { this.skeleton.leftFixedArea.container.unactiveAll(); } else if (this.parent.name === 'leftFixedArea') { this.skeleton.leftFloatArea.container.unactiveAll(); } + this._actived = true; + this.parent?.active(this); if (!this.inited) { this.inited = true; } diff --git a/packages/editor-skeleton/src/widget/widget-container.ts b/packages/editor-skeleton/src/widget/widget-container.ts index dceeabc5a..253dadb31 100644 --- a/packages/editor-skeleton/src/widget/widget-container.ts +++ b/packages/editor-skeleton/src/widget/widget-container.ts @@ -1,6 +1,6 @@ -import { obx, computed } from '@ali/lowcode-editor-core'; -import { isPanel } from './panel'; +import { obx, computed, makeObservable } from '@ali/lowcode-editor-core'; import { hasOwnProperty } from '@ali/lowcode-utils'; +import { isPanel } from './panel'; export interface WidgetItem { name: string; @@ -15,7 +15,7 @@ function isActiveable(obj: any): obj is Activeable { } export default class WidgetContainer { - @obx.val items: T[] = []; + @obx.shallow items: T[] = []; private maps: { [name: string]: T } = {}; @@ -32,8 +32,9 @@ export default class WidgetContainer boolean = () => true, private defaultSetCurrent: boolean = false, - // eslint-disable-next-line no-empty-function - ) {} + ) { + makeObservable(this); + } @computed get visible() { return this.checkVisible(); diff --git a/packages/editor-skeleton/src/widget/widget.ts b/packages/editor-skeleton/src/widget/widget.ts index b7b565070..9c3c58314 100644 --- a/packages/editor-skeleton/src/widget/widget.ts +++ b/packages/editor-skeleton/src/widget/widget.ts @@ -1,5 +1,5 @@ import { ReactNode, createElement } from 'react'; -import { obx } from '@ali/lowcode-editor-core'; +import { makeObservable, obx } from '@ali/lowcode-editor-core'; import { createContent, uniqueId } from '@ali/lowcode-utils'; import { WidgetConfig, IWidgetBaseConfig } from '../types'; import { Skeleton } from '../skeleton'; @@ -71,6 +71,7 @@ export default class Widget implements IWidget { readonly title: TitleContent; constructor(readonly skeleton: Skeleton, readonly config: WidgetConfig) { + makeObservable(this); const { props = {}, name } = config; this.name = name; this.align = props.align; diff --git a/packages/plugin-outline-pane/src/main.ts b/packages/plugin-outline-pane/src/main.ts index c9062ea68..94aa7409d 100644 --- a/packages/plugin-outline-pane/src/main.ts +++ b/packages/plugin-outline-pane/src/main.ts @@ -1,4 +1,4 @@ -import { computed, obx } from '@ali/lowcode-editor-core'; +import { computed, makeObservable, obx } from '@ali/lowcode-editor-core'; import { Designer, ISensor, @@ -17,12 +17,12 @@ import { contains, Node, } from '@ali/lowcode-designer'; +import { uniqueId } from '@ali/lowcode-utils'; +import { IEditor } from '@ali/lowcode-types'; import TreeNode from './tree-node'; import { IndentTrack } from './helper/indent-track'; import DwellTimer from './helper/dwell-timer'; -import { uniqueId } from '@ali/lowcode-utils'; import { Backup } from './views/backup-pane'; -import { IEditor } from '@ali/lowcode-types'; import { ITreeBoard, TreeMaster, getTreeMaster } from './tree-master'; export class OutlineMain implements ISensor, ITreeBoard, IScrollable { @@ -51,6 +51,7 @@ export class OutlineMain implements ISensor, ITreeBoard, IScrollable { readonly at: string | symbol; constructor(editor: IEditor, at: string | symbol) { + makeObservable(this); this.editor = editor; this.at = at; let inited = false; diff --git a/packages/plugin-outline-pane/src/tree-master.ts b/packages/plugin-outline-pane/src/tree-master.ts index 4e4049d0f..48f259ee4 100644 --- a/packages/plugin-outline-pane/src/tree-master.ts +++ b/packages/plugin-outline-pane/src/tree-master.ts @@ -1,4 +1,4 @@ -import { computed, obx } from '@ali/lowcode-editor-core'; +import { computed, makeObservable, obx } from '@ali/lowcode-editor-core'; import { Designer, isLocationChildrenDetail } from '@ali/lowcode-designer'; import TreeNode from './tree-node'; import { Tree } from './tree'; @@ -14,6 +14,7 @@ export class TreeMaster { readonly designer: Designer; constructor(designer: Designer) { + makeObservable(this); this.designer = designer; let startTime: any; designer.dragon.onDragstart(() => { @@ -71,7 +72,7 @@ export class TreeMaster { } } - @obx.val private boards = new Set(); + @obx.shallow private boards = new Set(); addBoard(board: ITreeBoard) { this.boards.add(board); @@ -81,7 +82,7 @@ export class TreeMaster { this.boards.delete(board); } - @computed hasVisibleTreeBoard() { + hasVisibleTreeBoard() { for (const item of this.boards) { if (item.visible && item.at !== Backup) { return true; diff --git a/packages/plugin-outline-pane/src/tree-node.ts b/packages/plugin-outline-pane/src/tree-node.ts index a38aa44a4..662501748 100644 --- a/packages/plugin-outline-pane/src/tree-node.ts +++ b/packages/plugin-outline-pane/src/tree-node.ts @@ -1,5 +1,5 @@ import { TitleContent, isI18nData } from '@ali/lowcode-types'; -import { computed, obx, intl } from '@ali/lowcode-editor-core'; +import { computed, obx, intl, makeObservable } from '@ali/lowcode-editor-core'; import { Node, DocumentModel, isLocationChildrenDetail, LocationChildrenDetail, Designer } from '@ali/lowcode-designer'; import { Tree } from './tree'; @@ -35,7 +35,7 @@ export default class TreeNode { /** * 是否是响应投放区 */ - @computed isResponseDropping(): boolean { + isResponseDropping(): boolean { const loc = this.node.document.dropLocation; if (!loc) { return false; @@ -43,7 +43,7 @@ export default class TreeNode { return loc.target === this.node; } - @computed isFocusingNode(): boolean { + isFocusingNode(): boolean { const loc = this.node.document.dropLocation; if (!loc) { return false; @@ -218,6 +218,7 @@ export default class TreeNode { readonly tree: Tree; constructor(tree: Tree, node: Node) { + makeObservable(this); this.tree = tree; this.document = node.document; this.designer = this.document.designer; diff --git a/packages/plugin-outline-pane/src/tree.ts b/packages/plugin-outline-pane/src/tree.ts index 894360cb7..18de35aa0 100644 --- a/packages/plugin-outline-pane/src/tree.ts +++ b/packages/plugin-outline-pane/src/tree.ts @@ -1,5 +1,5 @@ import { DocumentModel, Node } from '@ali/lowcode-designer'; -import { computed } from '@ali/lowcode-editor-core'; +import { computed, makeObservable } from '@ali/lowcode-editor-core'; import TreeNode from './tree-node'; export class Tree { @@ -15,6 +15,7 @@ export class Tree { } constructor(readonly document: DocumentModel) { + makeObservable(this); this.id = document.id; } diff --git a/packages/plugin-outline-pane/src/views/pane.tsx b/packages/plugin-outline-pane/src/views/pane.tsx index d17ee1929..6c2990308 100644 --- a/packages/plugin-outline-pane/src/views/pane.tsx +++ b/packages/plugin-outline-pane/src/views/pane.tsx @@ -10,10 +10,6 @@ import { IEditor } from '@ali/lowcode-types'; export class OutlinePane extends Component<{ config: any; editor: IEditor }> { private main = new OutlineMain(this.props.editor, this.props.config.name || this.props.config.pluginKey); - shouldComponentUpdate() { - return false; - } - componentWillUnmount() { this.main.purge(); } diff --git a/packages/plugin-outline-pane/src/views/root-tree-node.tsx b/packages/plugin-outline-pane/src/views/root-tree-node.tsx index efed91d78..198620b2d 100644 --- a/packages/plugin-outline-pane/src/views/root-tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/root-tree-node.tsx @@ -18,10 +18,6 @@ class ModalTreeNodeView extends Component<{ treeNode: TreeNode }> { this.modalNodesManager = props.treeNode.document.modalNodesManager; } - shouldComponentUpdate() { - return false; - } - hideAllNodes() { this.modalNodesManager.hideModalNodes(); } @@ -57,10 +53,6 @@ class ModalTreeNodeView extends Component<{ treeNode: TreeNode }> { @observer export default class RootTreeNodeView extends Component<{ treeNode: TreeNode }> { - shouldComponentUpdate() { - return false; - } - render() { const { treeNode } = this.props; const className = classNames('tree-node', { diff --git a/packages/plugin-outline-pane/src/views/tree-branches.tsx b/packages/plugin-outline-pane/src/views/tree-branches.tsx index 8cbf9db48..7a937f731 100644 --- a/packages/plugin-outline-pane/src/views/tree-branches.tsx +++ b/packages/plugin-outline-pane/src/views/tree-branches.tsx @@ -11,10 +11,6 @@ export default class TreeBranches extends Component<{ treeNode: TreeNode; isModal?: boolean; }> { - shouldComponentUpdate() { - return false; - } - render() { const { treeNode, isModal } = this.props; const { expanded } = treeNode; @@ -39,10 +35,6 @@ class TreeNodeChildren extends Component<{ treeNode: TreeNode; isModal?: boolean; }> { - shouldComponentUpdate() { - return false; - } - render() { const { treeNode, isModal } = this.props; const children: any = []; @@ -112,10 +104,6 @@ class TreeNodeChildren extends Component<{ class TreeNodeSlots extends Component<{ treeNode: TreeNode; }> { - shouldComponentUpdate() { - return false; - } - render() { const { treeNode } = this.props; if (!treeNode.hasSlots()) { diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index a22015cd5..1bea36f00 100644 --- a/packages/plugin-outline-pane/src/views/tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/tree-node.tsx @@ -10,10 +10,6 @@ export default class TreeNodeView extends Component<{ treeNode: TreeNode; isModal?: boolean; }> { - shouldComponentUpdate() { - return false; - } - render() { const { treeNode, isModal } = this.props; const className = classNames('tree-node', { diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 2015229ae..16e2bf0d7 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -176,10 +176,6 @@ export default class TreeTitle extends Component<{ @observer class LockBtn extends Component<{ treeNode: TreeNode }> { - shouldComponentUpdate() { - return false; - } - render() { const { treeNode } = this.props; return ( @@ -199,10 +195,6 @@ class LockBtn extends Component<{ treeNode: TreeNode }> { @observer class HideBtn extends Component<{ treeNode: TreeNode }> { - shouldComponentUpdate() { - return false; - } - render() { const { treeNode } = this.props; return ( @@ -224,10 +216,6 @@ class HideBtn extends Component<{ treeNode: TreeNode }> { @observer class ExpandBtn extends Component<{ treeNode: TreeNode }> { - shouldComponentUpdate() { - return false; - } - render() { const { treeNode } = this.props; if (!treeNode.expandable) { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 3e4a08a0b..2b7b82f2b 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -17,7 +17,8 @@ "@ali/lowcode-utils": "1.0.66", "@ali/recore-rax": "^1.2.4", "@ali/vu-css-style": "^1.0.2", - "@recore/obx": "^1.0.8", + "mobx": "^6.3.0", + "mobx-react": "^7.2.0", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", @@ -30,7 +31,6 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@babel/plugin-transform-react-jsx": "^7.10.4", - "@recore/obx": "^1.0.8", "@types/classnames": "^2.2.7", "@types/node": "^13.7.1", "@types/rax": "^1.0.0", diff --git a/packages/rax-simulator-renderer/src/renderer.ts b/packages/rax-simulator-renderer/src/renderer.ts index c21051fa2..883e782cd 100644 --- a/packages/rax-simulator-renderer/src/renderer.ts +++ b/packages/rax-simulator-renderer/src/renderer.ts @@ -2,7 +2,7 @@ import { BuiltinSimulatorRenderer, Component, DocumentModel, Node, NodeInstance import { ComponentSchema, NodeSchema, NpmInfo, RootSchema, TransformStage } from '@ali/lowcode-types'; import { Asset, compatibleLegaoSchema, cursor, isElement, isESModule, isPlainObject, isReactComponent, setNativeSelection } from '@ali/lowcode-utils'; import LowCodeRenderer from '@ali/lowcode-rax-renderer'; -import { computed, obx } from '@recore/obx'; +import { computed, observable as obx, untracked, makeObservable, configure } from 'mobx'; import DriverUniversal from 'driver-universal'; import { EventEmitter } from 'events'; import { createMemoryHistory, MemoryHistory } from 'history'; @@ -17,6 +17,7 @@ import { getClientRects } from './utils/get-client-rects'; import loader from './utils/loader'; import { parseQuery, withQueryParams } from './utils/url'; +configure({ enforceActions: 'never' }); const { Instance } = shared; export interface LibraryMap { @@ -110,6 +111,7 @@ export class DocumentInstance { private dispose?: () => void; constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) { + makeObservable(this); this.dispose = host.autorun(() => { // sync schema this._schema = document.export(TransformStage.Render); @@ -270,7 +272,8 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { }); const documentInstanceMap = new Map(); let initialEntry = '/'; - host.autorun(({ firstRun }) => { + let firstRun = true; + host.autorun(() => { this._documentInstances = host.project.documents.map((doc) => { let inst = documentInstanceMap.get(doc.id); if (!inst) { @@ -283,6 +286,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { const path = host.project.currentDocument ? documentInstanceMap.get(host.project.currentDocument.id)!.path : '/'; if (firstRun) { initialEntry = path; + firstRun = false; } else { if (this.history.location.pathname !== path) { this.history.replace(path); diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 35d23e204..1617a9538 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -22,7 +22,9 @@ "@recore/obx-react": "^1.0.7", "classnames": "^2.2.6", "react": "^16", - "react-dom": "^16.7.0" + "react-dom": "^16.7.0", + "mobx": "^6.3.0", + "mobx-react": "^7.2.0" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/src/index.ts b/packages/react-simulator-renderer/src/index.ts index 0be54766f..5f2ecae78 100644 --- a/packages/react-simulator-renderer/src/index.ts +++ b/packages/react-simulator-renderer/src/index.ts @@ -1,3 +1,4 @@ +import { runInAction } from 'mobx'; import renderer from './renderer'; if (typeof window !== 'undefined') { @@ -5,10 +6,12 @@ if (typeof window !== 'undefined') { } window.addEventListener('beforeunload', () => { - (window as any).LCSimulatorHost = null; - renderer.dispose?.(); - (window as any).SimulatorRenderer = null; - (window as any).ReactDOM.unmountComponentAtNode(document.getElementById('app')); + runInAction(() => { + (window as any).LCSimulatorHost = null; + renderer.dispose?.(); + (window as any).SimulatorRenderer = null; + (window as any).ReactDOM.unmountComponentAtNode(document.getElementById('app')); + }); }); export default renderer; diff --git a/packages/react-simulator-renderer/src/renderer-view.tsx b/packages/react-simulator-renderer/src/renderer-view.tsx index c17675c0f..caa4860ee 100644 --- a/packages/react-simulator-renderer/src/renderer-view.tsx +++ b/packages/react-simulator-renderer/src/renderer-view.tsx @@ -3,7 +3,7 @@ import { Router, Route, Switch } from 'react-router'; import cn from 'classnames'; import { Node } from '@ali/lowcode-designer'; import LowCodeRenderer from '@ali/lowcode-react-renderer'; -import { observer } from '@recore/obx-react'; +import { observer } from 'mobx-react'; import { isFromVC, getClosestNode } from '@ali/lowcode-utils'; import { SimulatorRendererContainer, DocumentInstance } from './renderer'; @@ -99,10 +99,6 @@ function getDeviceView(view: any, device: string, mode: string) { @observer class Layout extends Component<{ rendererContainer: SimulatorRendererContainer }> { - shouldComponentUpdate() { - return false; - } - render() { const { rendererContainer, children } = this.props; const { layout } = rendererContainer; @@ -133,10 +129,6 @@ class Renderer extends Component<{ rendererContainer: SimulatorRendererContainer, documentInstance: DocumentInstance, }> { - shouldComponentUpdate() { - return false; - } - render() { const { documentInstance, rendererContainer: renderer } = this.props; const { container } = documentInstance; diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index cfd506c4a..c212212dd 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -2,7 +2,7 @@ import React, { createElement, ReactInstance } from 'react'; import { render as reactRender } from 'react-dom'; import { host } from './host'; import SimulatorRendererView from './renderer-view'; -import { computed, obx, untracked } from '@recore/obx'; +import { computed, observable as obx, untracked, makeObservable, configure } from 'mobx'; import { getClientRects } from './utils/get-client-rects'; import { reactFindDOMNodes, FIBER_KEY } from './utils/react-find-dom-nodes'; import { @@ -28,7 +28,10 @@ import Leaf from './builtin-components/leaf'; import { withQueryParams, parseQuery } from './utils/url'; import { supportsQuickPropSetting, getUppermostPropKey, setInstancesProp } from './utils/misc'; const loader = new AssetLoader(); +const DELAY_THRESHOLD = 10; const FULL_RENDER_THRESHOLD = 500; +configure({ enforceActions: 'never' }); + export class DocumentInstance { public instancesMap = new Map(); @@ -40,9 +43,18 @@ export class DocumentInstance { private disposeFunctions: Array<() => void> = []; constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) { - const documentExportDisposer = host.autorun(() => { - this._schema = document.export(TransformStage.Render); - }); + makeObservable(this); + // 标识当前文档导出的状态,用来控制 reaction effect 是否执行 + let asleep = false; + const setDocSchema = (value?: any) => { + this._schema = value || document.export(TransformStage.Render); + }; + const documentExportDisposer = host.reaction(() => { + return document.export(TransformStage.Render); + }, (value) => { + if (asleep) return; + setDocSchema(value); + }, { delay: DELAY_THRESHOLD, fireImmediately: true }); this.disposeFunctions.push(documentExportDisposer); let tid: NodeJS.Timeout; this.disposeFunctions.push(host.onActivityEvent((data: ActivityData, ctx: any) => { @@ -53,7 +65,7 @@ export class DocumentInstance { if (tid) clearTimeout(tid); // 临时关闭全量计算 schema 的逻辑,在增量计算结束后,来一次全量计算 - documentExportDisposer.$obx.sleep(); + asleep = true; if (data.type === ActivityType.MODIFIED) { // 对于修改场景,优先判断是否能走「快捷设置」逻辑 if (supportsQuickPropSetting(data, this)) { @@ -69,7 +81,10 @@ export class DocumentInstance { // FIXME: 待补充逻辑 } - tid = setTimeout(() => documentExportDisposer.$obx.wakeup(true), FULL_RENDER_THRESHOLD); + tid = setTimeout(() => { + asleep = false; + setDocSchema(); + }, FULL_RENDER_THRESHOLD); // TODO: 调试增量模式,打开以下代码 // this._deltaData = data; // this._deltaMode = true; @@ -246,6 +261,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { } constructor() { + makeObservable(this); this.autoRender = host.autoRender; this.disposeFunctions.push(host.connect(this, () => { @@ -272,7 +288,8 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { })); const documentInstanceMap = new Map(); let initialEntry = '/'; - this.disposeFunctions.push(host.autorun(({ firstRun }) => { + let firstRun = true; + this.disposeFunctions.push(host.autorun(() => { this._documentInstances = host.project.documents.map((doc) => { let inst = documentInstanceMap.get(doc.id); if (!inst) { @@ -286,6 +303,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { : '/'; if (firstRun) { initialEntry = path; + firstRun = false; } else if (this.history.location.pathname !== path) { this.history.replace(path); } diff --git a/packages/vision-polyfill/src/env.ts b/packages/vision-polyfill/src/env.ts index 3c4b1bcd0..808e4bba7 100644 --- a/packages/vision-polyfill/src/env.ts +++ b/packages/vision-polyfill/src/env.ts @@ -9,7 +9,7 @@ interface ILiteralObject { } export class Env { - @obx.val envs: ILiteralObject = {}; + @obx.shallow envs: ILiteralObject = {}; private emitter: EventEmitter; diff --git a/packages/vision-polyfill/src/fields/fields.tsx b/packages/vision-polyfill/src/fields/fields.tsx index 296b8b681..d864d4a29 100644 --- a/packages/vision-polyfill/src/fields/fields.tsx +++ b/packages/vision-polyfill/src/fields/fields.tsx @@ -102,8 +102,8 @@ export class AccordionField extends VEField { constructor(props: IVEFieldProps) { super(props); this._generateClassNames(props); - if (this.props.onExpandChange) { - this.willDetach = this.props.onExpandChange(() => this.forceUpdate()); + if (props.onExpandChange) { + this.willDetach = props.onExpandChange(() => this.forceUpdate()); } } diff --git a/packages/vision-polyfill/src/i18n-util/index.js b/packages/vision-polyfill/src/i18n-util/index.js index f6bc3d606..46aabed87 100644 --- a/packages/vision-polyfill/src/i18n-util/index.js +++ b/packages/vision-polyfill/src/i18n-util/index.js @@ -18,7 +18,7 @@ class DocItem { constructor(parent, doc, unInitial) { this.parent = parent; const { use, ...strings } = doc; - this.doc = obx.val({ + this.doc = obx({ type: 'i18n', ...strings, }); diff --git a/tsconfig.json b/tsconfig.json index fce8ef03d..f0293f879 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,9 +31,9 @@ // skip type checking of declaration files "skipLibCheck": true, "baseUrl": "./packages", + "useDefineForClassFields": true, "paths": { - "@ali/lowcode-*": ["./*/src"], - "@ali/visualengine": ["./vision-preset/src"] + "@ali/lowcode-*": ["./*/src"] }, "outDir": "lib" },