Match-id-52f4df6a91e64babf85d2b4fe312dff944c9a1b2

This commit is contained in:
* 2022-04-01 16:19:42 +08:00 committed by *
parent 28dc82a7c4
commit 422726a88f
20 changed files with 108 additions and 119 deletions

View File

@ -23,6 +23,9 @@ import {
createElement, createElement,
cloneElement, cloneElement,
isValidElement, isValidElement,
act,
launchUpdateFromVNode as _launchUpdateFromVNode,
getProcessingVNode as _getProcessingVNode,
} from './src/external/Horizon'; } from './src/external/Horizon';
import { import {
@ -63,6 +66,9 @@ const Horizon = {
unstable_batchedUpdates, unstable_batchedUpdates,
findDOMNode, findDOMNode,
unmountComponentAtNode, unmountComponentAtNode,
act,
_launchUpdateFromVNode,
_getProcessingVNode,
}; };
export { export {
@ -95,6 +101,9 @@ export {
unstable_batchedUpdates, unstable_batchedUpdates,
findDOMNode, findDOMNode,
unmountComponentAtNode, unmountComponentAtNode,
act,
_launchUpdateFromVNode,
_getProcessingVNode,
}; };
export default Horizon; export default Horizon;

View File

@ -17,7 +17,6 @@ import {createContext} from '../renderer/components/context/CreateContext';
import {lazy} from '../renderer/components/Lazy'; import {lazy} from '../renderer/components/Lazy';
import {forwardRef} from '../renderer/components/ForwardRef'; import {forwardRef} from '../renderer/components/ForwardRef';
import {memo} from '../renderer/components/Memo'; import {memo} from '../renderer/components/Memo';
import hookMapping from '../renderer/hooks/HookMapping';
import { import {
useCallback, useCallback,
@ -30,6 +29,16 @@ import {
useRef, useRef,
useState, useState,
} from '../renderer/hooks/HookExternal'; } from '../renderer/hooks/HookExternal';
import {launchUpdateFromVNode, asyncUpdates} from '../renderer/TreeBuilder';
import {callRenderQueueImmediate} from '../renderer/taskExecutor/RenderQueue';
import {runAsyncEffects} from '../renderer/submit/HookEffectHandler';
import { getProcessingVNode } from '../renderer/hooks/BaseHook';
const act = (fun) => {
asyncUpdates(fun);
callRenderQueueImmediate();
runAsyncEffects();
}
export { export {
Children, Children,
@ -56,5 +65,7 @@ export {
createElement, createElement,
cloneElement, cloneElement,
isValidElement, isValidElement,
hookMapping, act,
launchUpdateFromVNode,
getProcessingVNode,
}; };

View File

@ -1,17 +1,15 @@
import type {ContextType} from '../Types'; import type {ContextType} from '../Types';
import hookMapping from './HookMapping';
import {useRefImpl} from './UseRefHook'; import {useRefImpl} from './UseRefHook';
import {useEffectImpl, useLayoutEffectImpl} from './UseEffectHook'; import {useEffectImpl, useLayoutEffectImpl} from './UseEffectHook';
import {useCallbackImpl} from './UseCallbackHook'; import {useCallbackImpl} from './UseCallbackHook';
import {useMemoImpl} from './UseMemoHook'; import {useMemoImpl} from './UseMemoHook';
import {useImperativeHandleImpl} from './UseImperativeHook'; import {useImperativeHandleImpl} from './UseImperativeHook';
import {useReducerImpl} from './UseReducerHook';
const { import {useStateImpl} from './UseStateHook';
UseContextHookMapping, import {getNewContext} from '../components/context/Context';
UseReducerHookMapping, import {getProcessingVNode} from './BaseHook';
UseStateHookMapping import {Ref, Trigger} from './HookType';
} = hookMapping;
type BasicStateAction<S> = ((S) => S) | S; type BasicStateAction<S> = ((S) => S) | S;
type Dispatch<A> = (A) => void; type Dispatch<A> = (A) => void;
@ -20,22 +18,23 @@ type Dispatch<A> = (A) => void;
export function useContext<T>( export function useContext<T>(
Context: ContextType<T>, Context: ContextType<T>,
): T { ): T {
return UseContextHookMapping.val.useContext(Context); const processingVNode = getProcessingVNode();
return getNewContext(processingVNode!, Context, true);
} }
export function useState<S>(initialState: (() => S) | S,): [S, Dispatch<BasicStateAction<S>>] { export function useState<S>(initialState: (() => S) | S,): [S, Dispatch<BasicStateAction<S>>] {
return UseStateHookMapping.val.useState(initialState); return useStateImpl(initialState);
} }
export function useReducer<S, I, A>( export function useReducer<S, I, A>(
reducer: (S, A) => S, reducer: (S, A) => S,
initialArg: I, initialArg: I,
init?: (I) => S, init?: (I) => S,
): [S, Dispatch<A>] { ): [S, Trigger<A>] | void {
return UseReducerHookMapping.val.useReducer(reducer, initialArg, init); return useReducerImpl(reducer, initialArg, init);
} }
export function useRef<T>(initialValue: T): {current: T} { export function useRef<T>(initialValue: T): Ref<T> {
return useRefImpl(initialValue); return useRefImpl(initialValue);
} }

View File

@ -1,22 +1,11 @@
import type {VNode} from '../Types'; import type {VNode} from '../Types';
import hookMapping from './HookMapping';
const {
UseStateHookMapping,
UseReducerHookMapping,
UseContextHookMapping,
} = hookMapping;
import {getNewContext} from '../components/context/Context';
import { import {
getLastTimeHook, getLastTimeHook,
getProcessingVNode,
setLastTimeHook, setLastTimeHook,
setProcessingVNode, setProcessingVNode,
setCurrentHook, getNextHook setCurrentHook, getNextHook
} from './BaseHook'; } from './BaseHook';
import {useStateImpl} from './UseStateHook';
import {useReducerImpl} from './UseReducerHook';
import {HookStage, setHookStage} from './HookStage'; import {HookStage, setHookStage} from './HookStage';
// hook对外入口 // hook对外入口
@ -29,9 +18,6 @@ export function exeFunctionHook<Props extends Record<string, any>, Arg>(
// 重置全局变量 // 重置全局变量
resetGlobalVariable(); resetGlobalVariable();
// 初始化hook实现函数
initHookMapping();
setProcessingVNode(processing); setProcessingVNode(processing);
processing.oldHooks = processing.hooks; processing.oldHooks = processing.hooks;
@ -71,8 +57,3 @@ function resetGlobalVariable() {
setCurrentHook(null); setCurrentHook(null);
} }
export function initHookMapping() {
UseContextHookMapping.val = {useContext: context => getNewContext(getProcessingVNode(), context, true)};
UseReducerHookMapping.val = {useReducer: useReducerImpl};
UseStateHookMapping.val = {useState: useStateImpl};
}

View File

@ -1,21 +0,0 @@
/**
*
*/
import type {
UseContextHookType,
UseReducerHookType,
UseStateHookType
} from '../Types';
const UseStateHookMapping: {val: (null | UseStateHookType)} = {val: null};
const UseReducerHookMapping: {val: (null | UseReducerHookType)} = {val: null};
const UseContextHookMapping: {val: (null | UseContextHookType)} = {val: null};
const hookMapping = {
UseStateHookMapping,
UseReducerHookMapping,
UseContextHookMapping,
}
export default hookMapping;

View File

@ -76,12 +76,14 @@ export function captureFunctionComponent(
); );
// 这里需要判断是否可以复用因为函数组件比起其他组价多了context和stateChange两个因素 // 这里需要判断是否可以复用因为函数组件比起其他组价多了context和stateChange两个因素
if (isCanReuse && !isStateChange()) { if (isCanReuse && !isStateChange() && !processing.isStoreChange) {
FlagUtils.removeFlag(processing, Update); FlagUtils.removeFlag(processing, Update);
return onlyUpdateChildVNodes(processing); return onlyUpdateChildVNodes(processing);
} }
processing.isStoreChange = false;
processing.child = createChildrenByDiff(processing, processing.child, newElements, !processing.isCreated); processing.child = createChildrenByDiff(processing, processing.child, newElements, !processing.isCreated);
return processing.child; return processing.child;
} }

View File

@ -66,6 +66,10 @@ export class VNode {
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode处理ref的时候使用 belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode处理ref的时候使用
// 状态管理器使用
isStoreChange: boolean;
functionToObserver: FunctionToObserver | null; // 记录这个函数组件依赖哪些Observer
constructor(tag: VNodeTag, props: any, key: null | string, realNode) { constructor(tag: VNodeTag, props: any, key: null | string, realNode) {
this.tag = tag; // 对应组件的类型比如ClassComponent等 this.tag = tag; // 对应组件的类型比如ClassComponent等
this.key = key; this.key = key;
@ -90,6 +94,8 @@ export class VNode {
this.depContexts = null; this.depContexts = null;
this.isDepContextChange = false; this.isDepContextChange = false;
this.oldHooks = null; this.oldHooks = null;
this.isStoreChange = false;
this.functionToObserver = null;
break; break;
case ClassComponent: case ClassComponent:
this.realNode = null; this.realNode = null;

View File

@ -1,9 +1,7 @@
import * as Horizon from '@cloudsop/horizon/index.ts'; import * as Horizon from '@cloudsop/horizon/index.ts';
import { act } from '../../jest/customMatcher';
describe('useContext Hook Test', () => { describe('useContext Hook Test', () => {
const { useState, useContext } = Horizon; const { useState, useContext, act, unmountComponentAtNode } = Horizon;
const { unmountComponentAtNode } = Horizon;
it('简单使用useContext', () => { it('简单使用useContext', () => {
const LanguageTypes = { const LanguageTypes = {

View File

@ -1,7 +1,6 @@
import * as Horizon from '@cloudsop/horizon/index.ts'; import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils'; import * as LogUtils from '../../jest/logUtils';
import { act } from '../../jest/customMatcher'; import { Text } from '../../jest/commonComponents';
import Text from '../../jest/Text';
describe('useEffect Hook Test', () => { describe('useEffect Hook Test', () => {
const { const {
@ -9,7 +8,8 @@ describe('useEffect Hook Test', () => {
useLayoutEffect, useLayoutEffect,
useState, useState,
memo, memo,
forwardRef forwardRef,
act,
} = Horizon; } = Horizon;
it('简单使用useEffect', () => { it('简单使用useEffect', () => {

View File

@ -1,13 +1,13 @@
import * as Horizon from '@cloudsop/horizon/index.ts'; import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils'; import * as LogUtils from '../../jest/logUtils';
import { act } from '../../jest/customMatcher'; import { Text } from '../../jest/commonComponents';
import Text from '../../jest/Text';
describe('useImperativeHandle Hook Test', () => { describe('useImperativeHandle Hook Test', () => {
const { const {
useState, useState,
useImperativeHandle, useImperativeHandle,
forwardRef forwardRef,
act,
} = Horizon; } = Horizon;
const { unmountComponentAtNode } = Horizon; const { unmountComponentAtNode } = Horizon;

View File

@ -1,13 +1,13 @@
import * as Horizon from '@cloudsop/horizon/index.ts'; import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils'; import * as LogUtils from '../../jest/logUtils';
import { act } from '../../jest/customMatcher'; import { Text } from '../../jest/commonComponents';
import Text from '../../jest/Text';
describe('useLayoutEffect Hook Test', () => { describe('useLayoutEffect Hook Test', () => {
const { const {
useState, useState,
useEffect, useEffect,
useLayoutEffect useLayoutEffect,
act,
} = Horizon; } = Horizon;
it('简单使用useLayoutEffect', () => { it('简单使用useLayoutEffect', () => {

View File

@ -1,6 +1,6 @@
import * as Horizon from '@cloudsop/horizon/index.ts'; import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils'; import * as LogUtils from '../../jest/logUtils';
import Text from '../../jest/Text'; import { Text } from '../../jest/commonComponents';
describe('useMemo Hook Test', () => { describe('useMemo Hook Test', () => {
const { useMemo, useState } = Horizon; const { useMemo, useState } = Horizon;

View File

@ -1,6 +1,6 @@
import * as Horizon from '@cloudsop/horizon/index.ts'; import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils'; import * as LogUtils from '../../jest/logUtils';
import Text from '../../jest/Text'; import { Text } from '../../jest/commonComponents';
describe('useRef Hook Test', () => { describe('useRef Hook Test', () => {
const { useState, useRef } = Horizon; const { useState, useRef } = Horizon;

View File

@ -1,14 +1,14 @@
import * as Horizon from '@cloudsop/horizon/index.ts'; import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils'; import * as LogUtils from '../../jest/logUtils';
import { act } from '../../jest/customMatcher'; import { Text } from '../../jest/commonComponents';
import Text from '../../jest/Text';
describe('useState Hook Test', () => { describe('useState Hook Test', () => {
const { const {
useState, useState,
forwardRef, forwardRef,
useImperativeHandle, useImperativeHandle,
memo memo,
act,
} = Horizon; } = Horizon;
it('简单使用useState', () => { it('简单使用useState', () => {

View File

@ -1,6 +1,5 @@
import * as Horizon from '@cloudsop/horizon/index.ts'; import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../jest/logUtils'; import * as LogUtils from '../jest/logUtils';
import { act } from '../jest/customMatcher';
describe('合成焦点事件', () => { describe('合成焦点事件', () => {
@ -43,4 +42,4 @@ describe('合成焦点事件', () => {
'onBlur: blur', 'onBlur: blur',
]); ]);
}) })
}) })

View File

@ -1,9 +0,0 @@
import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../jest/logUtils';
const Text = (props) => {
LogUtils.log(props.text);
return <p>{props.text}</p>;
};
export default Text;

View File

@ -0,0 +1,20 @@
import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from './logUtils';
export const App = (props) => {
const Parent = props.parent;
const Child = props.child;
return (
<div>
<Parent>
<Child />
</Parent>
</div>
);
}
export const Text = (props) => {
LogUtils.log(props.text);
return <p id={props.id}>{props.text}</p>;
}

View File

@ -1,33 +0,0 @@
import { runAsyncEffects } from '../../../libs/horizon/src/renderer/submit/HookEffectHandler';
import { callRenderQueueImmediate } from '../../../libs/horizon/src/renderer/taskExecutor/RenderQueue';
import { asyncUpdates } from '../../../libs/horizon/src/renderer/TreeBuilder';
function runAssertion(fn) {
try {
fn();
} catch (error) {
return {
pass: false,
message: () => error.message,
};
}
return { pass: true };
}
function toMatchValue(LogUtils, expectedValues) {
return runAssertion(() => {
const actualValues = LogUtils.getAndClear();
expect(actualValues).toEqual(expectedValues);
});
}
const act = (fun) => {
asyncUpdates(fun);
callRenderQueueImmediate();
runAsyncEffects();
}
module.exports = {
toMatchValue,
act
};

View File

@ -17,7 +17,27 @@ global.afterEach(() => {
LogUtils.clear(); LogUtils.clear();
}); });
function runAssertion(fn) {
try {
fn();
} catch (error) {
return {
pass: false,
message: () => error.message,
};
}
return { pass: true };
}
function toMatchValue(LogUtils, expectedValues) {
return runAssertion(() => {
const actualValues = LogUtils.getAndClear();
expect(actualValues).toEqual(expectedValues);
});
}
// 使Jest感知自定义匹配器 // 使Jest感知自定义匹配器
expect.extend({ expect.extend({
...require('./customMatcher'), toMatchValue,
}); });

View File

@ -9,7 +9,7 @@ export const stopBubbleOrCapture = (e, value) => {
export const getEventListeners = (dom) => { export const getEventListeners = (dom) => {
let ret = true let ret = true
let keyArray = []; let keyArray = [];
for (var key in dom) { for (let key in dom) {
keyArray.push(key); keyArray.push(key);
} }
try { try {
@ -23,4 +23,11 @@ export const getEventListeners = (dom) => {
} }
return ret; return ret;
}; };
export function triggerClickEvent(container, id) {
const event = new MouseEvent('click', {
bubbles: true,
});
container.querySelector(`#${id}`).dispatchEvent(event);
}