From 5d8eebf14487af249fdaab1bbf777799fca2901a Mon Sep 17 00:00:00 2001 From: * <*> Date: Wed, 24 Aug 2022 17:29:09 +0800 Subject: [PATCH] Match-id-cec2ce18d7d08f5b4f5642c57aaa799038a73223 --- .../src/horizonx/store/StoreHandler.ts | 8 +- .../src/renderer/render/BaseComponent.ts | 3 + .../multipleStores.test.tsx | 186 ++++++++++++++++++ 3 files changed, 192 insertions(+), 5 deletions(-) create mode 100644 scripts/__tests__/HorizonXText/StoreFunctionality/multipleStores.test.tsx diff --git a/libs/horizon/src/horizonx/store/StoreHandler.ts b/libs/horizon/src/horizonx/store/StoreHandler.ts index bdbf8f77..fc3ed6c9 100644 --- a/libs/horizon/src/horizonx/store/StoreHandler.ts +++ b/libs/horizon/src/horizonx/store/StoreHandler.ts @@ -204,7 +204,8 @@ export function createStore, C extend return createStoreHook(handler); } -function clearVNodeObservers(vNode) { +export function clearVNodeObservers(vNode) { + if(!vNode.observers) return; vNode.observers.forEach(observer => { observer.clearByVNode(vNode); }); @@ -220,10 +221,7 @@ function hookStore() { return; } - if (processingVNode.observers) { - // 清除上一次缓存的Observer依赖 - clearVNodeObservers(processingVNode); - } else { + if (!processingVNode.observers) { processingVNode.observers = new Set(); } diff --git a/libs/horizon/src/renderer/render/BaseComponent.ts b/libs/horizon/src/renderer/render/BaseComponent.ts index 1ea097d3..46fd1e0a 100644 --- a/libs/horizon/src/renderer/render/BaseComponent.ts +++ b/libs/horizon/src/renderer/render/BaseComponent.ts @@ -12,6 +12,7 @@ import { FlagUtils } from '../vnode/VNodeFlags'; import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator'; import componentRenders from './index'; import {setProcessingVNode} from '../GlobalVar'; +import { clearVNodeObservers } from '../../horizonx/store/StoreHandler'; // 复用vNode时,也需对stack进行处理 function handlerContext(processing: VNode) { @@ -55,6 +56,8 @@ export function captureVNode(processing: VNode): VNode | null { processing.shouldUpdate = false; setProcessingVNode(processing); + + clearVNodeObservers(processing); const child = component.captureRender(processing, shouldUpdate); setProcessingVNode(null); diff --git a/scripts/__tests__/HorizonXText/StoreFunctionality/multipleStores.test.tsx b/scripts/__tests__/HorizonXText/StoreFunctionality/multipleStores.test.tsx new file mode 100644 index 00000000..a9b933d9 --- /dev/null +++ b/scripts/__tests__/HorizonXText/StoreFunctionality/multipleStores.test.tsx @@ -0,0 +1,186 @@ +//@ts-ignore +import Horizon, { createStore } from '@cloudsop/horizon/index.ts'; +import { triggerClickEvent } from '../../jest/commonComponents'; +import { describe, beforeEach, afterEach, it, expect } from '@jest/globals'; + +const { unmountComponentAtNode } = Horizon; + +const useStore1 = createStore({ + state:{ counter:1 }, + actions:{ + add:(state)=>state.counter++, + reset: (state)=>state.counter=1 + } +}) + +const useStore2 = createStore({ + state:{ counter2:1 }, + actions:{ + add2:(state)=>state.counter2++, + reset: (state)=>state.counter2=1 + } +}) + +describe('Using multiple stores', () => { + let container: HTMLElement | null = null; + + const BUTTON_ID = 'btn'; + const BUTTON_ID2 = 'btn2'; + const RESULT_ID = 'result'; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + useStore1().reset(); + useStore2().reset(); + }); + + afterEach(() => { + unmountComponentAtNode(container); + container?.remove(); + container = null; + }); + + it('Should use multiple stores in class component', () => { + class App extends Horizon.Component{ + render(){ + const {counter,add} = useStore1(); + const store2 = useStore2(); + const {counter2, add2} = store2; + + return ( +
+ + +

{counter*counter2}

+
+ ) + } + } + + Horizon.render(, container); + + Horizon.act(() => { + triggerClickEvent(container, BUTTON_ID); + triggerClickEvent(container, BUTTON_ID); + triggerClickEvent(container, BUTTON_ID2); + triggerClickEvent(container, BUTTON_ID2); + }); + + expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('9'); + }); + + it('Should use use stores in cycles and multiple methods', () => { + interface App { + store:any, + store2:any + } + class App extends Horizon.Component{ + constructor(){ + super(); + this.store = useStore1(); + this.store2 = useStore2() + } + + render(){ + const {counter,add} = useStore1(); + const store2 = useStore2(); + const {counter2, add2} = store2; + + for(let i=0; i<100; i++){ + const {counter,add} = useStore1(); + const store2 = useStore2(); + const {counter2, add2} = store2; + } + + return ( +
+ + +

{counter*counter2}

+
+ ) + } + } + + Horizon.render(, container); + + Horizon.act(() => { + triggerClickEvent(container, BUTTON_ID); + triggerClickEvent(container, BUTTON_ID); + triggerClickEvent(container, BUTTON_ID2); + triggerClickEvent(container, BUTTON_ID2); + }); + + expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('9'); + }); + + it('Should use multiple stores in function component', () => { + function App() { + const {counter,add} = useStore1(); + const store2 = useStore2(); + const {counter2, add2} = store2; + + return ( +
+ + +

{counter*counter2}

+
+ ); + } + + Horizon.render(, container); + + Horizon.act(() => { + triggerClickEvent(container, BUTTON_ID); + triggerClickEvent(container, BUTTON_ID); + triggerClickEvent(container, BUTTON_ID2); + triggerClickEvent(container, BUTTON_ID2); + }); + + expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('9'); + }); +}); \ No newline at end of file