Match-id-caaaaddbbc27d8d6fc7beb95bf9fc050a8f86051

This commit is contained in:
* 2022-09-05 19:42:05 +08:00 committed by *
parent 93f529b55e
commit 072ceecd13
9 changed files with 199 additions and 217 deletions

View File

@ -25,7 +25,7 @@ import {
useReducer, useReducer,
useRef, useRef,
useState, useState,
useDebugValue useDebugValue,
} from './src/renderer/hooks/HookExternal'; } from './src/renderer/hooks/HookExternal';
import { asyncUpdates } from './src/renderer/TreeBuilder'; import { asyncUpdates } from './src/renderer/TreeBuilder';
import { callRenderQueueImmediate } from './src/renderer/taskExecutor/RenderQueue'; import { callRenderQueueImmediate } from './src/renderer/taskExecutor/RenderQueue';
@ -86,7 +86,7 @@ const Horizon = {
useStore, useStore,
clearStore, clearStore,
reduxAdapter, reduxAdapter,
watch watch,
}; };
export const version = __VERSION__; export const version = __VERSION__;
@ -127,7 +127,7 @@ export {
useStore, useStore,
clearStore, clearStore,
reduxAdapter, reduxAdapter,
watch watch,
}; };
export default Horizon; export default Horizon;

View File

@ -7,7 +7,6 @@ import { launchUpdateFromVNode } from '../../renderer/TreeBuilder';
import { getProcessingVNode } from '../../renderer/GlobalVar'; import { getProcessingVNode } from '../../renderer/GlobalVar';
import { VNode } from '../../renderer/vnode/VNode'; import { VNode } from '../../renderer/vnode/VNode';
export interface IObserver { export interface IObserver {
useProp: (key: string) => void; useProp: (key: string) => void;
addListener: (listener: () => void) => void; addListener: (listener: () => void) => void;
@ -26,14 +25,13 @@ export interface IObserver {
} }
export class Observer implements IObserver { export class Observer implements IObserver {
vNodeKeys = new WeakMap(); vNodeKeys = new WeakMap();
keyVNodes = new Map(); keyVNodes = new Map();
listeners: (() => void)[] = []; listeners: (() => void)[] = [];
watchers={} as {[key:string]:((key:string, oldValue:any, newValue:any)=>void)[]} watchers = {} as { [key: string]: ((key: string, oldValue: any, newValue: any) => void)[] };
useProp(key: string | symbol): void { useProp(key: string | symbol): void {
const processingVNode = getProcessingVNode(); const processingVNode = getProcessingVNode();

View File

@ -22,8 +22,8 @@ function get(rawObj: any[], key: string, receiver: any) {
observer.watchers[prop].push(handler); observer.watchers[prop].push(handler);
return () => { return () => {
observer.watchers[prop] = observer.watchers[prop].filter(cb => cb !== handler); observer.watchers[prop] = observer.watchers[prop].filter(cb => cb !== handler);
} };
} };
} }
if (isValidIntegerKey(key) || key === 'length') { if (isValidIntegerKey(key) || key === 'length') {

View File

@ -44,8 +44,8 @@ function get(rawObj: { size: number }, key: any, receiver: any): any {
observer.watchers[prop].push(handler); observer.watchers[prop].push(handler);
return () => { return () => {
observer.watchers[prop] = observer.watchers[prop].filter(cb => cb !== handler); observer.watchers[prop] = observer.watchers[prop].filter(cb => cb !== handler);
} };
} };
} }
return Reflect.get(rawObj, key, receiver); return Reflect.get(rawObj, key, receiver);

View File

@ -4,5 +4,5 @@ export function watch(stateVariable:any,listener:(state:any)=>void){
return () => { return () => {
stateVariable.removeListener(listener); stateVariable.removeListener(listener);
} };
} }

View File

@ -35,9 +35,7 @@ type StoreHandler<S extends object, A extends UserActions<S>, C extends UserComp
$queue: QueuedStoreActions<S, A>; $queue: QueuedStoreActions<S, A>;
$a: StoreActions<S, A>; $a: StoreActions<S, A>;
$c: UserComputedValues<S>; $c: UserComputedValues<S>;
} & { [K in keyof S]: S[K] } & } & { [K in keyof S]: S[K] } & { [K in keyof A]: Action<A[K], S> } & { [K in keyof C]: ReturnType<C[K]> };
{ [K in keyof A]: Action<A[K], S> } &
{ [K in keyof C]: ReturnType<C[K]> };
type PlannedAction<S extends object, F extends ActionFunction<S>> = { type PlannedAction<S extends object, F extends ActionFunction<S>> = {
action: string; action: string;
@ -103,7 +101,7 @@ export function createStore<S extends object, A extends UserActions<S>, C extend
const $a: Partial<StoreActions<S, A>> = {}; const $a: Partial<StoreActions<S, A>> = {};
const $queue: Partial<StoreActions<S, A>> = {}; const $queue: Partial<StoreActions<S, A>> = {};
const $c: Partial<ComputedValues<S, C>> = {}; const $c: Partial<ComputedValues<S, C>> = {};
const handler = ({ const handler = {
$subscribe, $subscribe,
$unsubscribe, $unsubscribe,
$a: $a as StoreActions<S, A>, $a: $a as StoreActions<S, A>,
@ -111,7 +109,7 @@ export function createStore<S extends object, A extends UserActions<S>, C extend
$c: $c as ComputedValues<S, C>, $c: $c as ComputedValues<S, C>,
$config: config, $config: config,
$queue: $queue as QueuedStoreActions<S, A>, $queue: $queue as QueuedStoreActions<S, A>,
} as unknown) as StoreHandler<S, A, C>; } as unknown as StoreHandler<S, A, C>;
function tryNextAction() { function tryNextAction() {
if (!plannedActions.length) { if (!plannedActions.length) {
@ -227,7 +225,7 @@ function hookStore() {
if (processingVNode.tag === FunctionComponent) { if (processingVNode.tag === FunctionComponent) {
// from FunctionComponent // from FunctionComponent
const vNodeRef = (useRef(null) as unknown) as { current: VNode }; const vNodeRef = useRef(null) as unknown as { current: VNode };
vNodeRef.current = processingVNode; vNodeRef.current = processingVNode;
useEffect(() => { useEffect(() => {

View File

@ -1,12 +1,6 @@
import type { VNode } from '../Types'; import type { VNode } from '../Types';
import { import { ContextProvider, DomComponent, DomPortal, TreeRoot, SuspenseComponent } from '../vnode/VNodeTags';
ContextProvider,
DomComponent,
DomPortal,
TreeRoot,
SuspenseComponent,
} from '../vnode/VNodeTags';
import { setContext, setNamespaceCtx } from '../ContextSaver'; import { setContext, setNamespaceCtx } from '../ContextSaver';
import { FlagUtils } from '../vnode/VNodeFlags'; import { FlagUtils } from '../vnode/VNodeFlags';
import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator'; import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator';
@ -40,11 +34,7 @@ export function captureVNode(processing: VNode): VNode | null {
if (processing.tag !== SuspenseComponent) { if (processing.tag !== SuspenseComponent) {
// 该vNode没有变化不用进入capture直接复用。 // 该vNode没有变化不用进入capture直接复用。
if ( if (!processing.isCreated && processing.oldProps === processing.props && !processing.shouldUpdate) {
!processing.isCreated &&
processing.oldProps === processing.props &&
!processing.shouldUpdate
) {
// 复用还需对stack进行处理 // 复用还需对stack进行处理
handlerContext(processing); handlerContext(processing);

View File

@ -1,24 +1,24 @@
import { createStore } from "@cloudsop/horizon/src/horizonx/store/StoreHandler"; import { createStore } from '@cloudsop/horizon/src/horizonx/store/StoreHandler';
import { watch } from "@cloudsop/horizon/src/horizonx/proxy/watch"; import { watch } from '@cloudsop/horizon/src/horizonx/proxy/watch';
describe("watch",()=>{ describe('watch', () => {
it('shouhld watch promitive state variable', async () => { it('shouhld watch promitive state variable', async () => {
const useStore = createStore({ const useStore = createStore({
state: { state: {
variable:'x' variable: 'x',
}, },
actions: { actions: {
change:(state)=>state.variable = "a" change: state => (state.variable = 'a'),
} },
}); });
const store = useStore(); const store = useStore();
let counter = 0; let counter = 0;
watch(store.$s,(state)=>{ watch(store.$s, state => {
counter++; counter++;
expect(state.variable).toBe('a'); expect(state.variable).toBe('a');
}) });
store.change(); store.change();
@ -27,11 +27,11 @@ describe("watch",()=>{
it('shouhld watch object variable', async () => { it('shouhld watch object variable', async () => {
const useStore = createStore({ const useStore = createStore({
state: { state: {
variable:'x' variable: 'x',
}, },
actions: { actions: {
change:(state)=>state.variable = "a" change: state => (state.variable = 'a'),
} },
}); });
const store = useStore(); const store = useStore();
@ -39,7 +39,7 @@ describe("watch",()=>{
store.$s.watch('variable', () => { store.$s.watch('variable', () => {
counter++; counter++;
}) });
store.change(); store.change();
@ -49,11 +49,11 @@ describe("watch",()=>{
it('shouhld watch array item', async () => { it('shouhld watch array item', async () => {
const useStore = createStore({ const useStore = createStore({
state: { state: {
arr:['x'] arr: ['x'],
}, },
actions: { actions: {
change:(state)=>state.arr[0]='a' change: state => (state.arr[0] = 'a'),
} },
}); });
const store = useStore(); const store = useStore();
@ -61,7 +61,7 @@ describe("watch",()=>{
store.arr.watch('0', () => { store.arr.watch('0', () => {
counter++; counter++;
}) });
store.change(); store.change();
@ -71,13 +71,11 @@ describe("watch",()=>{
it('shouhld watch collection item', async () => { it('shouhld watch collection item', async () => {
const useStore = createStore({ const useStore = createStore({
state: { state: {
collection:new Map([ collection: new Map([['a', 'a']]),
['a', 'a'],
])
}, },
actions: { actions: {
change:(state)=>state.collection.set('a','x') change: state => state.collection.set('a', 'x'),
} },
}); });
const store = useStore(); const store = useStore();
@ -85,7 +83,7 @@ describe("watch",()=>{
store.collection.watch('a', () => { store.collection.watch('a', () => {
counter++; counter++;
}) });
store.change(); store.change();
@ -96,12 +94,12 @@ describe("watch",()=>{
const useStore = createStore({ const useStore = createStore({
state: { state: {
bool1: true, bool1: true,
bool2:false bool2: false,
}, },
actions: { actions: {
toggle1:state=>state.bool1=!state.bool1, toggle1: state => (state.bool1 = !state.bool1),
toggle2:state=>state.bool2=!state.bool2 toggle2: state => (state.bool2 = !state.bool2),
} },
}); });
let counter1 = 0; let counter1 = 0;
@ -110,7 +108,7 @@ describe("watch",()=>{
watch(store.$s, () => { watch(store.$s, () => {
counterAll++; counterAll++;
}) });
store.$s.watch('bool1', () => { store.$s.watch('bool1', () => {
counter1++; counter1++;
@ -128,5 +126,5 @@ describe("watch",()=>{
expect(counter1).toBe(3); expect(counter1).toBe(3);
expect(counterAll).toBe(6); expect(counterAll).toBe(6);
}) });
}) });

View File

@ -8,18 +8,18 @@ const { unmountComponentAtNode } = Horizon;
const useStore1 = createStore({ const useStore1 = createStore({
state: { counter: 1 }, state: { counter: 1 },
actions: { actions: {
add:(state)=>state.counter++, add: state => state.counter++,
reset: (state)=>state.counter=1 reset: state => (state.counter = 1),
} },
}) });
const useStore2 = createStore({ const useStore2 = createStore({
state: { counter2: 1 }, state: { counter2: 1 },
actions: { actions: {
add2:(state)=>state.counter2++, add2: state => state.counter2++,
reset: (state)=>state.counter2=1 reset: state => (state.counter2 = 1),
} },
}) });
describe('Using multiple stores', () => { describe('Using multiple stores', () => {
let container: HTMLElement | null = null; let container: HTMLElement | null = null;
@ -65,9 +65,11 @@ describe('Using multiple stores', () => {
> >
add add
</button> </button>
<p id={RESULT_ID}>{counter} {counter2}</p> <p id={RESULT_ID}>
{counter} {counter2}
</p>
</div> </div>
) );
} }
} }
@ -76,28 +78,25 @@ describe('Using multiple stores', () => {
expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('1 1'); expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('1 1');
Horizon.act(() => { Horizon.act(() => {
triggerClickEvent(container, BUTTON_ID); triggerClickEvent(container, BUTTON_ID);
}); });
expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 1'); expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 1');
Horizon.act(() => { Horizon.act(() => {
triggerClickEvent(container, BUTTON_ID2); triggerClickEvent(container, BUTTON_ID2);
}); });
expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 2'); expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 2');
}); });
it('Should use use stores in cycles and multiple methods', () => { it('Should use use stores in cycles and multiple methods', () => {
interface App { interface App {
store:any, store: any;
store2:any store2: any;
} }
class App extends Horizon.Component { class App extends Horizon.Component {
constructor() { constructor() {
super(); super();
this.store = useStore1(); this.store = useStore1();
this.store2 = useStore2() this.store2 = useStore2();
} }
render() { render() {
@ -129,9 +128,11 @@ describe('Using multiple stores', () => {
> >
add add
</button> </button>
<p id={RESULT_ID}>{counter} {counter2}</p> <p id={RESULT_ID}>
{counter} {counter2}
</p>
</div> </div>
) );
} }
} }
@ -140,16 +141,13 @@ describe('Using multiple stores', () => {
expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('1 1'); expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('1 1');
Horizon.act(() => { Horizon.act(() => {
triggerClickEvent(container, BUTTON_ID); triggerClickEvent(container, BUTTON_ID);
}); });
expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 1'); expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 1');
Horizon.act(() => { Horizon.act(() => {
triggerClickEvent(container, BUTTON_ID2); triggerClickEvent(container, BUTTON_ID2);
}); });
expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 2'); expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 2');
}); });
it('Should use multiple stores in function component', () => { it('Should use multiple stores in function component', () => {
@ -176,7 +174,9 @@ describe('Using multiple stores', () => {
> >
add add
</button> </button>
<p id={RESULT_ID}>{counter} {counter2}</p> <p id={RESULT_ID}>
{counter} {counter2}
</p>
</div> </div>
); );
} }
@ -186,13 +186,11 @@ describe('Using multiple stores', () => {
expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('1 1'); expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('1 1');
Horizon.act(() => { Horizon.act(() => {
triggerClickEvent(container, BUTTON_ID); triggerClickEvent(container, BUTTON_ID);
}); });
expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 1'); expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 1');
Horizon.act(() => { Horizon.act(() => {
triggerClickEvent(container, BUTTON_ID2); triggerClickEvent(container, BUTTON_ID2);
}); });
expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 2'); expect(document.getElementById(RESULT_ID)?.innerHTML).toBe('2 2');
}); });