From d3260a4d9492a2ae753d7e8daee001afee733adc Mon Sep 17 00:00:00 2001
From: * <8>
Date: Mon, 21 Mar 2022 14:54:32 +0800
Subject: [PATCH 01/13] Match-id-1da48726eef4a520b10fbe5a29d1b869a4b29678
---
.eslintrc.js | 11 +-
babel.config.js | 7 +-
.../HookTest/UseCallback.test.js | 10 +-
.../ComponentTest/HookTest/UseContext.test.js | 14 +--
.../ComponentTest/HookTest/UseEffect.test.js | 110 +++++++++---------
.../HookTest/UseImperativeHandle.test.js | 26 ++---
.../HookTest/UseLayoutEffect.test.js | 18 ++-
.../ComponentTest/HookTest/UseMemo.test.js | 24 ++--
.../ComponentTest/HookTest/UseReducer.test.js | 10 +-
.../ComponentTest/HookTest/UseRef.test.js | 10 +-
.../ComponentTest/HookTest/UseState.test.js | 26 ++---
scripts/__tests__/jest/Text.js | 2 +-
scripts/webpack/webpack.pro.js | 4 +-
13 files changed, 133 insertions(+), 139 deletions(-)
diff --git a/.eslintrc.js b/.eslintrc.js
index cbc6dfd8..79557bf5 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -29,7 +29,6 @@ module.exports = {
node: true,
es6: true,
},
-
rules: {
'accessor-pairs': 'off',
'brace-style': ['error', '1tbs'],
@@ -42,4 +41,14 @@ module.exports = {
'no-for-of-loops/no-for-of-loops': 'error',
'no-function-declare-after-return/no-function-declare-after-return': 'error',
},
+ overrides: [
+ {
+ files: [
+ 'scripts/__tests__/**/*.js'
+ ],
+ globals: {
+ container: true
+ },
+ },
+ ],
};
diff --git a/babel.config.js b/babel.config.js
index b7da15b0..37c7ac9e 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -1,6 +1,6 @@
module.exports = {
presets: [
- '@babel/react',
+ '@babel/react',
'@babel/preset-typescript',
['@babel/preset-env', { targets: { node: 'current' } }]
],
@@ -30,7 +30,10 @@ module.exports = {
['@babel/plugin-proposal-private-methods', { 'loose': true }],
['@babel/plugin-proposal-private-property-in-object', { 'loose': true }],
'@babel/plugin-syntax-jsx',
- '@babel/plugin-transform-react-jsx',
+ ['@babel/plugin-transform-react-jsx', {
+ pragma: 'Horizon.createElement',
+ pragmaFrag: 'Horizon.Fragment'
+ }],
'@babel/plugin-transform-flow-strip-types',
],
};
diff --git a/scripts/__tests__/ComponentTest/HookTest/UseCallback.test.js b/scripts/__tests__/ComponentTest/HookTest/UseCallback.test.js
index 071c4512..e2d51e9d 100644
--- a/scripts/__tests__/ComponentTest/HookTest/UseCallback.test.js
+++ b/scripts/__tests__/ComponentTest/HookTest/UseCallback.test.js
@@ -1,9 +1,7 @@
-/* eslint-disable no-undef */
-import * as React from '../../../../libs/horizon/src/external/Horizon';
-import * as HorizonDOM from '../../../../libs/horizon/src/dom/DOMExternal';
+import * as Horizon from '@cloudsop/horizon/index.ts';
describe('useCallback Hook Test', () => {
- const { useState, useCallback } = React;
+ const { useState, useCallback } = Horizon;
it('测试useCallback', () => {
const App = (props) => {
@@ -18,7 +16,7 @@ describe('useCallback Hook Test', () => {
>
)
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(container.querySelector('p').innerHTML).toBe('0');
// 点击按钮触发num加1
container.querySelector('button').click();
@@ -27,7 +25,7 @@ describe('useCallback Hook Test', () => {
container.querySelector('button').click();
expect(container.querySelector('p').innerHTML).toBe('1');
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(container.querySelector('p').innerHTML).toBe('1');
// 依赖项有变化,点击按钮num增加
container.querySelector('button').click();
diff --git a/scripts/__tests__/ComponentTest/HookTest/UseContext.test.js b/scripts/__tests__/ComponentTest/HookTest/UseContext.test.js
index 89482aff..d94443b7 100644
--- a/scripts/__tests__/ComponentTest/HookTest/UseContext.test.js
+++ b/scripts/__tests__/ComponentTest/HookTest/UseContext.test.js
@@ -1,11 +1,9 @@
-/* eslint-disable no-undef */
-import * as React from '../../../../libs/horizon/src/external/Horizon';
-import * as HorizonDOM from '../../../../libs/horizon/src/dom/DOMExternal';
+import * as Horizon from '@cloudsop/horizon/index.ts';
import { act } from '../../jest/customMatcher';
describe('useContext Hook Test', () => {
- const { useState, useContext } = React;
- const { unmountComponentAtNode } = HorizonDOM;
+ const { useState, useContext } = Horizon;
+ const { unmountComponentAtNode } = Horizon;
it('简单使用useContext', () => {
const LanguageTypes = {
@@ -13,7 +11,7 @@ describe('useContext Hook Test', () => {
JAVASCRIPT: 'JavaScript',
};
const defaultValue = { type: LanguageTypes.JAVASCRIPT };
- const SystemLanguageContext = React.createContext(defaultValue);
+ const SystemLanguageContext = Horizon.createContext(defaultValue);
const SystemLanguageProvider = ({ type, children }) => {
return (
@@ -38,11 +36,11 @@ describe('useContext Hook Test', () => {
)
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
// 测试当Provider未提供时,获取到的默认值'JavaScript'。
expect(container.querySelector('p').innerHTML).toBe('JavaScript');
unmountComponentAtNode(container);
- HorizonDOM.render(, container);
+ Horizon.render(, container);
// 测试当Provider提供时,可以获取到Provider的值'Java'。
expect(container.querySelector('p').innerHTML).toBe('Java');
// 测试当Provider改变时,可以获取到最新Provider的值。
diff --git a/scripts/__tests__/ComponentTest/HookTest/UseEffect.test.js b/scripts/__tests__/ComponentTest/HookTest/UseEffect.test.js
index e4a52d65..b1bc34fe 100644
--- a/scripts/__tests__/ComponentTest/HookTest/UseEffect.test.js
+++ b/scripts/__tests__/ComponentTest/HookTest/UseEffect.test.js
@@ -1,18 +1,16 @@
-/* eslint-disable no-undef */
-import * as React from '../../../../libs/horizon/src/external/Horizon';
-import * as HorizonDOM from '../../../../libs/horizon/src/dom/DOMExternal';
+import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils';
import { act } from '../../jest/customMatcher';
import Text from '../../jest/Text';
describe('useEffect Hook Test', () => {
- const {
- useEffect,
- useLayoutEffect,
- useState,
- memo,
- forwardRef
- } = React;
+ const {
+ useEffect,
+ useLayoutEffect,
+ useState,
+ memo,
+ forwardRef
+ } = Horizon;
it('简单使用useEffect', () => {
const App = () => {
@@ -27,7 +25,7 @@ describe('useEffect Hook Test', () => {
>
)
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(document.getElementById('p').style.display).toBe('block');
// 点击按钮触发num加1
container.querySelector('button').click();
@@ -42,7 +40,7 @@ describe('useEffect Hook Test', () => {
}
act(() => {
- HorizonDOM.render(, container, () => {
+ Horizon.render(, container, () => {
LogUtils.log('num effect');
});
// 第一次渲染为同步,所以同步执行的可以写在act里做判断
@@ -50,7 +48,7 @@ describe('useEffect Hook Test', () => {
expect(container.textContent).toBe('op');
});
act(() => {
- HorizonDOM.render(null, container, () => {
+ Horizon.render(null, container, () => {
LogUtils.log('num effect89');
});
// 第二次渲染为异步,所以同步执行的不可以写在act里做判断,act里拿到的为空数组
@@ -72,7 +70,7 @@ describe('useEffect Hook Test', () => {
}
const na = ;
// 必须设置key值,否则在diff的时候na会被视为不同组件
- HorizonDOM.render([, na], container);
+ Horizon.render([, na], container);
expect(LogUtils.getAndClear()).toEqual([
'App',
'NewApp'
@@ -80,7 +78,7 @@ describe('useEffect Hook Test', () => {
expect(container.textContent).toBe('AppNewApp');
expect(LogUtils.getAndClear()).toEqual([]);
// 在执行新的render前,会执行完上一次render的useEffect,所以LogUtils会加入'NewApp effect'。
- HorizonDOM.render([na], container);
+ Horizon.render([na], container);
expect(LogUtils.getAndClear()).toEqual(['NewApp effect']);
expect(container.textContent).toBe('NewApp');
expect(LogUtils.getAndClear()).toEqual([]);
@@ -104,7 +102,7 @@ describe('useEffect Hook Test', () => {
return ;
}
// 必须设置key值,否则在diff的时候na会被视为不同组件
- HorizonDOM.render([, ], container);
+ Horizon.render([, ], container);
expect(LogUtils.getAndClear()).toEqual([
'App',
'NewApp',
@@ -122,7 +120,7 @@ describe('useEffect Hook Test', () => {
const App = () => {
useLayoutEffect(() => {
LogUtils.log('App Layout effect');
- HorizonDOM.render(, newContainer);
+ Horizon.render(, newContainer);
});
return ;
}
@@ -133,7 +131,7 @@ describe('useEffect Hook Test', () => {
return ;
}
// 必须设置key值,否则在diff的时候na会被视为不同组件
- HorizonDOM.render([, ], container);
+ Horizon.render([, ], container);
expect(LogUtils.getAndClear()).toEqual([
'App',
'NewApp',
@@ -153,13 +151,13 @@ describe('useEffect Hook Test', () => {
return ;
}
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
expect(LogUtils.getAndClear()).toEqual(['num: 0', 'callback effect']);
expect(container.textContent).toEqual('num: 0');
})
expect(LogUtils.getAndClear()).toEqual(['First effect [0]']);
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
})
// 此时异步执行,act执行完后会执行新render的useEffect
@@ -182,13 +180,13 @@ describe('useEffect Hook Test', () => {
return ;
}
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
expect(LogUtils.getAndClear()).toEqual(['num: 0', 'callback effect']);
expect(container.textContent).toEqual('num: 0');
})
expect(LogUtils.getAndClear()).toEqual(['First effect [0]', 'Second effect [0]']);
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
})
// 第二次render时异步执行,act保证所有效果都已更新,所以先常规记录日志
// 然后记录useEffect的日志
@@ -231,7 +229,7 @@ describe('useEffect Hook Test', () => {
}
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
expect(LogUtils.getAndClear()).toEqual([
'num: 0,word: App',
'num Layouteffect [0]',
@@ -246,21 +244,21 @@ describe('useEffect Hook Test', () => {
act(() => {
// 此时word改变,num不变
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
});
expect(LogUtils.getAndClear()).toEqual([
- 'num: 0,word: React',
+ 'num: 0,word: Horizon',
'word Layouteffect destroy',
- 'word Layouteffect [React]',
+ 'word Layouteffect [Horizon]',
'callback effect',
// 最后执行异步的
'word effect destroy',
- 'word effect [React]',
+ 'word effect [Horizon]',
]);
act(() => {
// 此时num和word的所有effect都销毁
- HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
+ Horizon.render(null, container, () => LogUtils.log('callback effect'));
});
expect(LogUtils.getAndClear()).toEqual([
'num Layouteffect destroy',
@@ -284,7 +282,7 @@ describe('useEffect Hook Test', () => {
}
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
expect(LogUtils.getAndClear()).toEqual([
'num: 0',
'callback effect'
@@ -296,7 +294,7 @@ describe('useEffect Hook Test', () => {
]);
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
});
expect(LogUtils.getAndClear()).toEqual([
'num: 1',
@@ -309,7 +307,7 @@ describe('useEffect Hook Test', () => {
expect(LogUtils.getAndClear()).toEqual([]);
act(() => {
- HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
+ Horizon.render(null, container, () => LogUtils.log('callback effect'));
});
expect(LogUtils.getAndClear()).toEqual([
'callback effect',
@@ -331,7 +329,7 @@ describe('useEffect Hook Test', () => {
}
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
expect(LogUtils.getAndClear()).toEqual([
'num: 0',
'callback effect'
@@ -343,7 +341,7 @@ describe('useEffect Hook Test', () => {
]);
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
});
expect(LogUtils.getAndClear()).toEqual([
'num: 1',
@@ -354,7 +352,7 @@ describe('useEffect Hook Test', () => {
expect(LogUtils.getAndClear()).toEqual([]);
act(() => {
- HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
+ Horizon.render(null, container, () => LogUtils.log('callback effect'));
});
expect(LogUtils.getAndClear()).toEqual([
'callback effect',
@@ -367,7 +365,7 @@ describe('useEffect Hook Test', () => {
it('useEffect里使用useState(1', () => {
let setNum;
const App = () => {
- const [num, _setNum] = React.useState(0);
+ const [num, _setNum] = Horizon.useState(0);
useEffect(() => {
LogUtils.log(`num effect [${num}]`);
setNum = () => _setNum(1);
@@ -382,7 +380,7 @@ describe('useEffect Hook Test', () => {
}
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
expect(LogUtils.getAndClear()).toEqual([
'num: 0',
'num Layouteffect [0]',
@@ -415,7 +413,7 @@ describe('useEffect Hook Test', () => {
return ;
}
- HorizonDOM.render(, container, () => LogUtils.log('App callback effect'));
+ Horizon.render(, container, () => LogUtils.log('App callback effect'));
expect(LogUtils.getAndClear()).toEqual(['Num: 0', 'App callback effect']);
expect(container.textContent).toEqual('Num: 0');
act(() => {
@@ -445,7 +443,7 @@ describe('useEffect Hook Test', () => {
return ;
})
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
expect(LogUtils.getAndClear()).toEqual([
0,
'callback effect'
@@ -456,7 +454,7 @@ describe('useEffect Hook Test', () => {
// 不会重新渲染
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
});
expect(LogUtils.getAndClear()).toEqual(['callback effect']);
expect(container.textContent).toEqual('0');
@@ -475,7 +473,7 @@ describe('useEffect Hook Test', () => {
expect(LogUtils.getAndClear()).toEqual([]);
act(() => {
- HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
+ Horizon.render(null, container, () => LogUtils.log('callback effect'));
});
expect(LogUtils.getAndClear()).toEqual([
'callback effect',
@@ -497,7 +495,7 @@ describe('useEffect Hook Test', () => {
return ;
}, compare)
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
expect(LogUtils.getAndClear()).toEqual([
0,
'callback effect'
@@ -508,7 +506,7 @@ describe('useEffect Hook Test', () => {
// 不会重新渲染
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
});
expect(LogUtils.getAndClear()).toEqual(['callback effect']);
expect(container.textContent).toEqual('0');
@@ -516,7 +514,7 @@ describe('useEffect Hook Test', () => {
// 会重新渲染
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
});
expect(LogUtils.getAndClear()).toEqual([
1,
@@ -529,7 +527,7 @@ describe('useEffect Hook Test', () => {
expect(LogUtils.getAndClear()).toEqual([]);
act(() => {
- HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
+ Horizon.render(null, container, () => LogUtils.log('callback effect'));
});
expect(LogUtils.getAndClear()).toEqual(['callback effect', 'num effect destroy 1']);
expect(container.textContent).toEqual('');
@@ -550,7 +548,7 @@ describe('useEffect Hook Test', () => {
return ;
}
act(() => {
- HorizonDOM.render(, container, () =>
+ Horizon.render(, container, () =>
LogUtils.log('App callback effect'),
);
expect(LogUtils.getAndClear()).toEqual(['Number: 0', 'App callback effect']);
@@ -560,7 +558,7 @@ describe('useEffect Hook Test', () => {
expect(LogUtils.getAndClear()).toEqual(['throw Error']);
act(() => {
- HorizonDOM.render(null, container, () =>
+ Horizon.render(null, container, () =>
LogUtils.log('App callback effect'),
);
});
@@ -592,14 +590,14 @@ describe('useEffect Hook Test', () => {
}
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('num effect'));
+ Horizon.render(, container, () => LogUtils.log('num effect'));
expect(LogUtils.getAndClear()).toEqual(['Number: 0', 'num effect']);
expect(container.textContent).toBe('Number: 0');
});
expect(LogUtils.getAndClear()).toEqual(['num effect [0]']);
act(() => {
- HorizonDOM.render(null, container, () => LogUtils.log('num effect'));
+ Horizon.render(null, container, () => LogUtils.log('num effect'));
});
expect(LogUtils.getAndClear()).toEqual(['num effect', 'num effect destroy 0']);
expect(container.textContent).toBe('');
@@ -618,7 +616,7 @@ describe('useEffect Hook Test', () => {
return ;
}
- HorizonDOM.render(, container, () => LogUtils.log('num effect'));
+ Horizon.render(, container, () => LogUtils.log('num effect'));
expect(LogUtils.getAndClear()).toEqual(['Number: 0', 'num effect']);
expect(container.textContent).toBe('Number: 0');
@@ -648,13 +646,13 @@ describe('useEffect Hook Test', () => {
}
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('num effect'));
+ Horizon.render(, container, () => LogUtils.log('num effect'));
expect(LogUtils.getAndClear()).toEqual(['useEffect', 'num effect']);
});
expect(LogUtils.getAndClear()).toEqual(['effect']);
act(() => {
- HorizonDOM.render(null, container);
+ Horizon.render(null, container);
});
// 不会处理setNum(1)
expect(LogUtils.getAndClear()).toEqual(['effect destroy']);
@@ -663,7 +661,7 @@ describe('useEffect Hook Test', () => {
it('当组件的更新方法在卸载函数中,组件的子组件更新不会告警', () => {
const App = () => {
LogUtils.log('App');
- const appRef = React.createRef(null);
+ const appRef = Horizon.createRef(null);
useEffect(() => {
LogUtils.log('App effect');
return () => {
@@ -686,7 +684,7 @@ describe('useEffect Hook Test', () => {
AppChild = forwardRef(AppChild);
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('num effect'));
+ Horizon.render(, container, () => LogUtils.log('num effect'));
expect(LogUtils.getAndClear()).toEqual([
'App',
'AppChild',
@@ -696,7 +694,7 @@ describe('useEffect Hook Test', () => {
expect(LogUtils.getAndClear()).toEqual(['Child effect', 'App effect']);
act(() => {
- HorizonDOM.render(null, container);
+ Horizon.render(null, container);
});
// 销毁时执行appRef.current(1)不会报错
expect(LogUtils.getAndClear()).toEqual(['App effect destroy']);
@@ -722,7 +720,7 @@ describe('useEffect Hook Test', () => {
}
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('num effect'));
+ Horizon.render(, container, () => LogUtils.log('num effect'));
expect(LogUtils.getAndClear()).toEqual([
'App',
'AppChild',
@@ -732,7 +730,7 @@ describe('useEffect Hook Test', () => {
expect(LogUtils.getAndClear()).toEqual(['Child effect']);
act(() => {
- HorizonDOM.render(null, container);
+ Horizon.render(null, container);
});
// 销毁时执行 props.setNum(1);不会报错
expect(LogUtils.getAndClear()).toEqual(['Child effect destroy']);
diff --git a/scripts/__tests__/ComponentTest/HookTest/UseImperativeHandle.test.js b/scripts/__tests__/ComponentTest/HookTest/UseImperativeHandle.test.js
index 10ce8623..b7f5d6e8 100644
--- a/scripts/__tests__/ComponentTest/HookTest/UseImperativeHandle.test.js
+++ b/scripts/__tests__/ComponentTest/HookTest/UseImperativeHandle.test.js
@@ -1,6 +1,4 @@
-/* eslint-disable no-undef */
-import * as React from '../../../../libs/horizon/src/external/Horizon';
-import * as HorizonDOM from '../../../../libs/horizon/src/dom/DOMExternal';
+import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils';
import { act } from '../../jest/customMatcher';
import Text from '../../jest/Text';
@@ -10,9 +8,9 @@ describe('useImperativeHandle Hook Test', () => {
useState,
useImperativeHandle,
forwardRef
- } = React;
- const { unmountComponentAtNode } = HorizonDOM;
-
+ } = Horizon;
+ const { unmountComponentAtNode } = Horizon;
+
it('测试useImperativeHandle', () => {
let App = (props, ref) => {
@@ -28,9 +26,9 @@ describe('useImperativeHandle Hook Test', () => {
App = forwardRef(App);
App1 = forwardRef(App1);
- const counter = React.createRef(null);
- const counter1 = React.createRef(null);
- HorizonDOM.render(, container);
+ const counter = Horizon.createRef(null);
+ const counter1 = Horizon.createRef(null);
+ Horizon.render(, container);
expect(counter.current.num).toBe(0);
act(() => {
counter.current.setNum(1);
@@ -40,7 +38,7 @@ describe('useImperativeHandle Hook Test', () => {
// 清空container
unmountComponentAtNode(container);
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(counter1.current.num1).toBe(0);
act(() => {
counter1.current.setNum1(1);
@@ -64,9 +62,9 @@ describe('useImperativeHandle Hook Test', () => {
App = forwardRef(App);
App1 = forwardRef(App1);
- const counter = React.createRef(null);
- const counter1 = React.createRef(null);
- HorizonDOM.render(, container);
+ const counter = Horizon.createRef(null);
+ const counter1 = Horizon.createRef(null);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual([0]);
expect(counter.current.num).toBe(0);
act(() => {
@@ -78,7 +76,7 @@ describe('useImperativeHandle Hook Test', () => {
// 清空container
unmountComponentAtNode(container);
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual([0]);
expect(counter1.current.num1).toBe(0);
act(() => {
diff --git a/scripts/__tests__/ComponentTest/HookTest/UseLayoutEffect.test.js b/scripts/__tests__/ComponentTest/HookTest/UseLayoutEffect.test.js
index ec7eda11..84226eac 100644
--- a/scripts/__tests__/ComponentTest/HookTest/UseLayoutEffect.test.js
+++ b/scripts/__tests__/ComponentTest/HookTest/UseLayoutEffect.test.js
@@ -1,6 +1,4 @@
-/* eslint-disable no-undef */
-import * as React from '../../../../libs/horizon/src/external/Horizon';
-import * as HorizonDOM from '../../../../libs/horizon/src/dom/DOMExternal';
+import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils';
import { act } from '../../jest/customMatcher';
import Text from '../../jest/Text';
@@ -10,7 +8,7 @@ describe('useLayoutEffect Hook Test', () => {
useState,
useEffect,
useLayoutEffect
- } = React;
+ } = Horizon;
it('简单使用useLayoutEffect', () => {
const App = () => {
@@ -25,7 +23,7 @@ describe('useLayoutEffect Hook Test', () => {
>
)
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(document.getElementById('p').style.display).toBe('none');
container.querySelector('button').click();
expect(container.querySelector('p').style.display).toBe('inline');
@@ -38,7 +36,7 @@ describe('useLayoutEffect Hook Test', () => {
});
return ;
}
- HorizonDOM.render(, container, () => LogUtils.log('Sync effect'));
+ Horizon.render(, container, () => LogUtils.log('Sync effect'));
expect(LogUtils.getAndClear()).toEqual([
1,
// 同步在渲染之后
@@ -47,7 +45,7 @@ describe('useLayoutEffect Hook Test', () => {
]);
expect(container.querySelector('p').innerHTML).toBe('1');
// 更新
- HorizonDOM.render(, container, () => LogUtils.log('Sync effect'));
+ Horizon.render(, container, () => LogUtils.log('Sync effect'));
expect(LogUtils.getAndClear()).toEqual([
2,
'LayoutEffect',
@@ -74,7 +72,7 @@ describe('useLayoutEffect Hook Test', () => {
}
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
expect(LogUtils.getAndClear()).toEqual([
'num: 0',
'num Layouteffect [0]',
@@ -85,7 +83,7 @@ describe('useLayoutEffect Hook Test', () => {
// 更新
act(() => {
- HorizonDOM.render(, container, () => LogUtils.log('callback effect'));
+ Horizon.render(, container, () => LogUtils.log('callback effect'));
})
expect(LogUtils.getAndClear()).toEqual([
// 异步effect
@@ -103,7 +101,7 @@ describe('useLayoutEffect Hook Test', () => {
]);
act(() => {
- HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
+ Horizon.render(null, container, () => LogUtils.log('callback effect'));
})
expect(LogUtils.getAndClear()).toEqual([
// 同步Layouteffect销毁
diff --git a/scripts/__tests__/ComponentTest/HookTest/UseMemo.test.js b/scripts/__tests__/ComponentTest/HookTest/UseMemo.test.js
index 294ae787..41882449 100644
--- a/scripts/__tests__/ComponentTest/HookTest/UseMemo.test.js
+++ b/scripts/__tests__/ComponentTest/HookTest/UseMemo.test.js
@@ -1,11 +1,9 @@
-/* eslint-disable no-undef */
-import * as React from '../../../../libs/horizon/src/external/Horizon';
-import * as HorizonDOM from '../../../../libs/horizon/src/dom/DOMExternal';
+import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils';
import Text from '../../jest/Text';
describe('useMemo Hook Test', () => {
- const { useMemo, useState } = React;
+ const { useMemo, useState } = Horizon;
it('测试useMemo', () => {
let setMemo;
@@ -24,7 +22,7 @@ describe('useMemo Hook Test', () => {
>
);
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(container.querySelector('p').innerHTML).toBe('App');
expect(container.querySelector('#p').innerHTML).toBe('1');
// 修改useMemo的依赖项,num会加一,text会改变。
@@ -49,26 +47,26 @@ describe('useMemo Hook Test', () => {
}, [props._num]);
return ;
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual([
0,
1
]);
expect(container.textContent).toBe('1');
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual([
1,
2
]);
expect(container.textContent).toBe('2');
- HorizonDOM.render(, container);
+ Horizon.render(, container);
// 不会触发useMemo
expect(LogUtils.getAndClear()).toEqual([2]);
expect(container.textContent).toBe('2');
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual([
2,
3
@@ -92,16 +90,16 @@ describe('useMemo Hook Test', () => {
return 2;
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual(['num 1', 1]);
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual(['num 1', 1]);
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual(['num 1', 1]);
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual(['num 2', 2]);
});
});
diff --git a/scripts/__tests__/ComponentTest/HookTest/UseReducer.test.js b/scripts/__tests__/ComponentTest/HookTest/UseReducer.test.js
index 29c228c1..a6a427ba 100644
--- a/scripts/__tests__/ComponentTest/HookTest/UseReducer.test.js
+++ b/scripts/__tests__/ComponentTest/HookTest/UseReducer.test.js
@@ -1,10 +1,8 @@
-/* eslint-disable no-undef */
-import * as React from '../../../../libs/horizon/src/external/Horizon';
-import * as HorizonDOM from '../../../../libs/horizon/src/dom/DOMExternal';
+import * as Horizon from '@cloudsop/horizon/index.ts';
describe('useReducer Hook Test', () => {
- const { useReducer } = React;
-
+ const { useReducer } = Horizon;
+
it('简单使用useReducer', () => {
const intlCar = { logo: '', price: 0 };
let dispatch;
@@ -46,7 +44,7 @@ describe('useReducer Hook Test', () => {
)
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(container.querySelector('p').innerHTML).toBe('');
expect(container.querySelector('#senP').innerHTML).toBe('0');
// 触发bmw
diff --git a/scripts/__tests__/ComponentTest/HookTest/UseRef.test.js b/scripts/__tests__/ComponentTest/HookTest/UseRef.test.js
index 39e663bb..b2bab667 100644
--- a/scripts/__tests__/ComponentTest/HookTest/UseRef.test.js
+++ b/scripts/__tests__/ComponentTest/HookTest/UseRef.test.js
@@ -1,11 +1,9 @@
-/* eslint-disable no-undef */
-import * as React from '../../../../libs/horizon/src/external/Horizon';
-import * as HorizonDOM from '../../../../libs/horizon/src/dom/DOMExternal';
+import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils';
import Text from '../../jest/Text';
describe('useRef Hook Test', () => {
- const { useState, useRef } = React;
+ const { useState, useRef } = Horizon;
it('测试useRef', () => {
const App = () => {
@@ -22,7 +20,7 @@ describe('useRef Hook Test', () => {
>
)
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(container.querySelector('p').innerHTML).toBe('1');
expect(container.querySelector('#sp').innerHTML).toBe('1');
// 点击按钮触发num加1,ref不变
@@ -46,7 +44,7 @@ describe('useRef Hook Test', () => {
)
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual([1]);
expect(container.querySelector('p').innerHTML).toBe('1');
// 点击按钮触发ref.current加1
diff --git a/scripts/__tests__/ComponentTest/HookTest/UseState.test.js b/scripts/__tests__/ComponentTest/HookTest/UseState.test.js
index adccf421..b9e1d950 100644
--- a/scripts/__tests__/ComponentTest/HookTest/UseState.test.js
+++ b/scripts/__tests__/ComponentTest/HookTest/UseState.test.js
@@ -1,6 +1,4 @@
-/* eslint-disable no-undef */
-import * as React from '../../../../libs/horizon/src/external/Horizon';
-import * as HorizonDOM from '../../../../libs/horizon/src/dom/DOMExternal';
+import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../../jest/logUtils';
import { act } from '../../jest/customMatcher';
import Text from '../../jest/Text';
@@ -11,7 +9,7 @@ describe('useState Hook Test', () => {
forwardRef,
useImperativeHandle,
memo
- } = React;
+ } = Horizon;
it('简单使用useState', () => {
const App = () => {
@@ -23,7 +21,7 @@ describe('useState Hook Test', () => {
>
)
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(container.querySelector('p').innerHTML).toBe('0');
// 点击按钮触发num加1
container.querySelector('button').click();
@@ -45,7 +43,7 @@ describe('useState Hook Test', () => {
);
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(container.querySelector('p').innerHTML).toBe('00');
container.querySelector('p').click();
expect(container.querySelector('p').innerHTML).toBe('12');
@@ -67,7 +65,7 @@ describe('useState Hook Test', () => {
);
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(container.querySelector('p').innerHTML).toBe('0');
container.querySelector('p').click();
expect(container.querySelector('p').innerHTML).toBe('2');
@@ -82,7 +80,7 @@ describe('useState Hook Test', () => {
setNum = _setNum;
return ;
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(container.querySelector('p').innerHTML).toBe('0');
expect(LogUtils.getAndClear()).toEqual([0]);
// useState修改state 时,设置相同的值,函数组件不会重新渲染
@@ -101,8 +99,8 @@ describe('useState Hook Test', () => {
return {num}
;
})
- const ref = React.createRef(null);
- HorizonDOM.render(, container);
+ const ref = Horizon.createRef(null);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual([1]);
expect(container.querySelector('p').innerHTML).toBe('1');
// 设置num为3
@@ -119,11 +117,11 @@ describe('useState Hook Test', () => {
setNum = _setNum;
return ;
})
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual([0]);
expect(container.querySelector('p').innerHTML).toBe('0');
// 不会重新渲染
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual([]);
expect(container.querySelector('p').innerHTML).toBe('0');
// 会重新渲染
@@ -153,7 +151,7 @@ describe('useState Hook Test', () => {
return ;
}
- HorizonDOM.render(, container);
+ Horizon.render(, container);
expect(LogUtils.getAndClear()).toEqual(['Number: 0, Count: 0']);
expect(container.textContent).toBe('Number: 0, Count: 0');
act(() => {
@@ -164,7 +162,7 @@ describe('useState Hook Test', () => {
expect(container.textContent).toBe('Number: 1, Count: 2');
expect(() => {
- HorizonDOM.render(, container);
+ Horizon.render(, container);
}).toThrow(
'Hooks are less than expected, please check whether the hook is written in the condition.',
);
diff --git a/scripts/__tests__/jest/Text.js b/scripts/__tests__/jest/Text.js
index 24d63cf8..781c6d5a 100644
--- a/scripts/__tests__/jest/Text.js
+++ b/scripts/__tests__/jest/Text.js
@@ -1,4 +1,4 @@
-import * as React from '../../../libs/horizon/src/external/Horizon';
+import * as Horizon from '@cloudsop/horizon/index.ts';
import * as LogUtils from '../jest/logUtils';
const Text = (props) => {
diff --git a/scripts/webpack/webpack.pro.js b/scripts/webpack/webpack.pro.js
index b57b8eba..3494e99e 100644
--- a/scripts/webpack/webpack.pro.js
+++ b/scripts/webpack/webpack.pro.js
@@ -45,11 +45,11 @@ const cjs = {
...plugins,
new CopyWebpackPlugin([
{
- from: path.join(__dirname, '../../libs/index.js'),
+ from: path.join(__dirname, '../../libs/horizon/index.js'),
to: path.join(__dirname, '../../build/horizon/index.js'),
},
{
- from: path.join(__dirname, '../../libs/package.json'),
+ from: path.join(__dirname, '../../libs/horizon/package.json'),
to: path.join(__dirname, '../../build/horizon/package.json'),
}
])
From 55dac3b56baa13b8b66de746d2af5a2bd3b5c065 Mon Sep 17 00:00:00 2001
From: * <8>
Date: Mon, 21 Mar 2022 17:50:18 +0800
Subject: [PATCH 02/13] Match-id-580af01343fa5bba627a04ab667a638ec280a603
---
libs/horizon/src/renderer/components/BaseClassComponent.ts | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/libs/horizon/src/renderer/components/BaseClassComponent.ts b/libs/horizon/src/renderer/components/BaseClassComponent.ts
index 74f6df80..b5b202c2 100644
--- a/libs/horizon/src/renderer/components/BaseClassComponent.ts
+++ b/libs/horizon/src/renderer/components/BaseClassComponent.ts
@@ -1,18 +1,22 @@
/**
* Component的api setState和forceUpdate在实例生成阶段实现
*/
+
class Component {
props: P;
context: C;
state: S | null;
refs: any;
- setState: any;
forceUpdate: any;
constructor(props: P, context: C) {
this.props = props;
this.context = context;
}
+
+ setState(state: S) {
+ console.error('Cant not call `this.setState` in the constructor of class component, it will do nothing')
+ }
}
// 兼容三方件 react-lifecycles-compat,它会读取 isReactComponent 属性值,不添加会导致 eview-ui 官网白屏
From ea44e30933164f272d7411e6d6b637d220a9083c Mon Sep 17 00:00:00 2001
From: * <8>
Date: Tue, 22 Mar 2022 10:26:15 +0800
Subject: [PATCH 03/13] Match-id-5935bd5d4b80a4524d2b9a839ca106c4249ad3e5
---
.eslintignore | 1 +
.eslintrc.js | 5 +++++
libs/horizon/index.d.ts | 5 ++++-
libs/horizon/src/renderer/components/BaseClassComponent.ts | 7 +++++--
tsconfig.json | 4 ++--
5 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/.eslintignore b/.eslintignore
index 25439044..60feb237 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,2 +1,3 @@
**/node_modules
build/
+*.d.ts
diff --git a/.eslintrc.js b/.eslintrc.js
index 79557bf5..46239631 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,6 +1,8 @@
module.exports = {
extends: [
'eslint:recommended',
+ "plugin:@typescript-eslint/eslint-recommended",
+ "plugin:@typescript-eslint/recommended",
'prettier',
],
root: true,
@@ -41,6 +43,9 @@ module.exports = {
'no-for-of-loops/no-for-of-loops': 'error',
'no-function-declare-after-return/no-function-declare-after-return': 'error',
},
+ globals: {
+ isDev: true
+ },
overrides: [
{
files: [
diff --git a/libs/horizon/index.d.ts b/libs/horizon/index.d.ts
index 4c54c7c5..bab6684d 100644
--- a/libs/horizon/index.d.ts
+++ b/libs/horizon/index.d.ts
@@ -1 +1,4 @@
-declare var isDev: any;
+/*
+ 区分是否开发者模式
+ */
+declare var isDev: boolean;
diff --git a/libs/horizon/src/renderer/components/BaseClassComponent.ts b/libs/horizon/src/renderer/components/BaseClassComponent.ts
index b5b202c2..c8fcf9a9 100644
--- a/libs/horizon/src/renderer/components/BaseClassComponent.ts
+++ b/libs/horizon/src/renderer/components/BaseClassComponent.ts
@@ -2,7 +2,7 @@
* Component的api setState和forceUpdate在实例生成阶段实现
*/
-class Component
{
+class Component
{
props: P;
context: C;
state: S | null;
@@ -15,12 +15,15 @@ class Component
{
}
setState(state: S) {
- console.error('Cant not call `this.setState` in the constructor of class component, it will do nothing')
+ if (isDev) {
+ console.error('Cant not call `this.setState` in the constructor of class component, it will do nothing');
+ }
}
}
// 兼容三方件 react-lifecycles-compat,它会读取 isReactComponent 属性值,不添加会导致 eview-ui 官网白屏
Component.prototype.isReactComponent = true;
+
/**
* 支持PureComponent
*/
diff --git a/tsconfig.json b/tsconfig.json
index e05c4501..e85c8cac 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -34,8 +34,8 @@
},
"include": [
"./libs/**/src/**/*.ts",
- "libs/index.d.ts"
+ "libs/horizon/index.d.ts"
],
"exclude": ["node_modules", "**/*.spec.ts", "dev"],
- "types": ["node"],
+ "types": ["node"]
}
From dfa9ad8f020bfedba20ee8c351ee27773135ec09 Mon Sep 17 00:00:00 2001
From: * <8>
Date: Wed, 23 Mar 2022 10:15:58 +0800
Subject: [PATCH 04/13] Match-id-2c5b3e4e34c044c80842fd08377d49c00014c684
---
libs/horizon/src/renderer/TreeBuilder.ts | 33 +++++++------------
.../renderer/components/BaseClassComponent.ts | 2 +-
.../src/renderer/diff/nodeDiffComparator.ts | 10 +++---
.../src/renderer/render/MemoComponent.ts | 7 ++--
.../src/renderer/render/SuspenseComponent.ts | 5 +--
libs/horizon/src/renderer/utils/vNodePath.ts | 15 +++++++++
.../src/renderer/vnode/VNodeCreator.ts | 9 ++---
7 files changed, 46 insertions(+), 35 deletions(-)
create mode 100644 libs/horizon/src/renderer/utils/vNodePath.ts
diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts
index 9bf2455a..721bbff6 100644
--- a/libs/horizon/src/renderer/TreeBuilder.ts
+++ b/libs/horizon/src/renderer/TreeBuilder.ts
@@ -35,6 +35,7 @@ import {
updateParentsChildShouldUpdate,
updateShouldUpdateOfTree
} from './vnode/VNodeShouldUpdate';
+import { getPathArr } from './utils/vNodePath';
// 不可恢复错误
let unrecoverableErrorDuringBuild: any = null;
@@ -142,11 +143,11 @@ function handleError(root, error): void {
}
// 判断数组中节点的path的idx元素是否都相等
-function isEqualByIndex(idx: number, nodes: Array) {
- let val = nodes[0].path[idx];
- for (let i = 1; i < nodes.length; i++) {
- let node = nodes[i];
- if (val !== node.path[idx]) {
+function isEqualByIndex(idx: number, pathArrays: string[][]) {
+ const first = pathArrays[0][idx];
+ for (let i = 1; i < pathArrays.length; i++) {
+ const pathArr = pathArrays[i];
+ if (idx >= pathArr.length || first !== pathArr[idx]) {
return false;
}
}
@@ -179,29 +180,19 @@ export function calcStartUpdateVNode(treeRoot: VNode) {
return treeRoot;
}
- // 找到路径最短的长度
- let minPath = toUpdateNodes[0].path.length;
- for (let i = 1; i < toUpdateNodes.length; i++) {
- let pathLen = toUpdateNodes[i].path.length;
- if (pathLen < minPath) {
- minPath = pathLen;
- }
- }
-
+ const pathArrays = toUpdateNodes.map(node => getPathArr(node));
// 找出开始不相等的idx
- let idx = 0;
- for (; idx < minPath; idx++) {
- if (!isEqualByIndex(idx, toUpdateNodes)) {
- break;
- }
+ let commonPathEndIndex = 0;
+ while (isEqualByIndex(commonPathEndIndex, pathArrays)) {
+ commonPathEndIndex++;
}
// 得到相等的路径
- const startNodePath = toUpdateNodes[0].path.slice(0, idx);
+ const startNodePath = pathArrays[0].slice(0, commonPathEndIndex);
let node = treeRoot;
for (let i = 1; i < startNodePath.length; i++) {
const pathIndex = Number(startNodePath[i]);
- node = getChildByIndex(node, pathIndex);
+ node = getChildByIndex(node, pathIndex)!;
}
return node;
diff --git a/libs/horizon/src/renderer/components/BaseClassComponent.ts b/libs/horizon/src/renderer/components/BaseClassComponent.ts
index c8fcf9a9..08b6fb30 100644
--- a/libs/horizon/src/renderer/components/BaseClassComponent.ts
+++ b/libs/horizon/src/renderer/components/BaseClassComponent.ts
@@ -1,13 +1,13 @@
/**
* Component的api setState和forceUpdate在实例生成阶段实现
*/
-
class Component {
props: P;
context: C;
state: S | null;
refs: any;
forceUpdate: any;
+ isReactComponent: boolean;
constructor(props: P, context: C) {
this.props = props;
diff --git a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts
index db920f79..2b97612f 100644
--- a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts
+++ b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts
@@ -17,6 +17,7 @@ import {
isObjectType,
} from './DiffTools';
import { travelChildren } from '../vnode/VNodeUtils';
+import { markVNodePath } from '../utils/vNodePath';
enum DiffCategory {
TEXT_NODE = 'TEXT_NODE',
@@ -241,7 +242,7 @@ function diffArrayNodesHandler(
prevNewNode.next = newNode;
newNode.cIndex = prevNewNode.cIndex + 1;
}
- newNode.path = newNode.parent.path + newNode.cIndex;
+ markVNodePath(newNode);
prevNewNode = newNode;
}
@@ -477,7 +478,7 @@ function setVNodesCIndex(startChild: VNode | null, startIdx: number) {
while (node !== null) {
node.cIndex = idx;
- node.path = node.parent.path + node.cIndex;
+ markVNodePath(node);
node = node.next;
idx++;
}
@@ -528,7 +529,7 @@ function diffStringNodeHandler(
}
newTextNode.parent = parentNode;
newTextNode.cIndex = 0;
- newTextNode.path = newTextNode.parent.path + newTextNode.cIndex;
+ markVNodePath(newTextNode);
return newTextNode;
}
@@ -606,7 +607,8 @@ function diffObjectNodeHandler(
resultNode.parent = parentNode;
resultNode.cIndex = 0;
- resultNode.path = resultNode.parent.path + resultNode.cIndex;
+ markVNodePath(resultNode);
+
if (startDelVNode) {
deleteVNodes(parentNode, startDelVNode);
}
diff --git a/libs/horizon/src/renderer/render/MemoComponent.ts b/libs/horizon/src/renderer/render/MemoComponent.ts
index 84daa883..99a34364 100644
--- a/libs/horizon/src/renderer/render/MemoComponent.ts
+++ b/libs/horizon/src/renderer/render/MemoComponent.ts
@@ -8,6 +8,7 @@ import {
TYPE_PROFILER,
TYPE_STRICT_MODE,
} from '../../external/JSXElementType';
+import { markVNodePath } from '../utils/vNodePath';
export function bubbleRender() {}
@@ -20,7 +21,7 @@ export function captureMemoComponent(
const newProps = mergeDefaultProps(Component, processing.props);
if (processing.isCreated) {
- let newChild = null;
+ let newChild: VNode | null = null;
const type = Component.type;
if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) {
newChild = createFragmentVNode(null, newProps.children);
@@ -29,7 +30,7 @@ export function captureMemoComponent(
}
newChild.parent = processing;
newChild.ref = processing.ref;
- newChild.path = newChild.parent.path + newChild.cIndex;
+ markVNodePath(newChild);
processing.child = newChild;
return newChild;
@@ -48,7 +49,7 @@ export function captureMemoComponent(
const newChild = updateVNode(firstChild, newProps);
newChild.parent = processing;
newChild.cIndex = 0;
- newChild.path = newChild.parent.path + newChild.cIndex;
+ markVNodePath(newChild);
newChild.ref = processing.ref;
processing.child = newChild;
diff --git a/libs/horizon/src/renderer/render/SuspenseComponent.ts b/libs/horizon/src/renderer/render/SuspenseComponent.ts
index cdc2f4a4..3e7bdcb2 100644
--- a/libs/horizon/src/renderer/render/SuspenseComponent.ts
+++ b/libs/horizon/src/renderer/render/SuspenseComponent.ts
@@ -11,6 +11,7 @@ import {pushForceUpdate} from '../UpdateHandler';
import {launchUpdateFromVNode, tryRenderFromRoot} from '../TreeBuilder';
import {updateShouldUpdateOfTree} from '../vnode/VNodeShouldUpdate';
import {getContextChangeCtx} from '../ContextSaver';
+import { markVNodePath } from '../utils/vNodePath';
export enum SuspenseChildStatus {
Init = '',
@@ -44,7 +45,7 @@ function createFallback(processing: VNode, fallbackChildren) {
fallbackFragment.parent = processing;
fallbackFragment.eIndex = 1;
fallbackFragment.cIndex = 1;
- fallbackFragment.path = fallbackFragment.parent.path + fallbackFragment.cIndex;
+ markVNodePath(fallbackFragment);
processing.suspenseChildStatus = SuspenseChildStatus.ShowFallback;
return fallbackFragment;
@@ -76,7 +77,7 @@ function createSuspenseChildren(processing: VNode, newChildren) {
childFragment.parent = processing;
childFragment.cIndex = 0;
- childFragment.path = childFragment.parent.path + childFragment.cIndex;
+ markVNodePath(childFragment);
processing.child = childFragment;
processing.promiseResolve = false;
return processing.child;
diff --git a/libs/horizon/src/renderer/utils/vNodePath.ts b/libs/horizon/src/renderer/utils/vNodePath.ts
new file mode 100644
index 00000000..5f8b78ac
--- /dev/null
+++ b/libs/horizon/src/renderer/utils/vNodePath.ts
@@ -0,0 +1,15 @@
+import { VNode } from '../vnode/VNode';
+
+const PATH_DELIMITER = ',';
+
+/**
+ * 标记VNode在VNode树中的路径
+ * @param vNode
+ */
+export function markVNodePath(vNode: VNode) {
+ vNode.path = `${vNode.parent!.path}${PATH_DELIMITER}${vNode.cIndex}`;
+}
+
+export function getPathArr(vNode: VNode) {
+ return vNode.path.split(PATH_DELIMITER);
+}
diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts
index 865f791e..8c76d63c 100644
--- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts
+++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts
@@ -26,6 +26,7 @@ import {
} from '../../external/JSXElementType';
import { VNode } from './VNode';
import { JSXElement } from '../Types';
+import { markVNodePath } from '../utils/vNodePath';
const typeLazyMap = {
[TYPE_FORWARD_REF]: ForwardRef,
@@ -135,7 +136,7 @@ export function createUndeterminedVNode(type, key, props) {
export function createTreeRootVNode(container) {
const vNode = newVirtualNode(TreeRoot, null, null, container);
- vNode.path += 0;
+ vNode.path = '0';
vNode.updates = [];
return vNode;
}
@@ -147,7 +148,7 @@ export function createVNode(tag: VNodeTag | string, ...secondArg) {
case TreeRoot:
// 创建treeRoot
vNode = newVirtualNode(TreeRoot, null, null, secondArg[0]);
- vNode.path += 0;
+ vNode.path = '0';
vNode.updates = [];
break;
@@ -178,7 +179,7 @@ export function onlyUpdateChildVNodes(processing: VNode): VNode | null {
let child: VNode | null = processing.child;
while (child !== null) {
updateVNode(child, child.props);
- child.path = child.parent.path + child.cIndex;
+ markVNodePath(child);
child = child.next;
}
}
@@ -209,7 +210,7 @@ export function onlyUpdateChildVNodes(processing: VNode): VNode | null {
while (queue.length) {
const vNode = queue.shift()!;
- vNode.path = vNode.parent.path + vNode.cIndex;
+ markVNodePath(vNode);
putChildrenIntoQueue(vNode)
}
From c6f1debb0338533b97144cc51db505baac9f246d Mon Sep 17 00:00:00 2001
From: * <8>
Date: Wed, 23 Mar 2022 10:28:58 +0800
Subject: [PATCH 05/13] Match-id-d0e5ae18684fb3ef46de9d8df3806ec5e84da25b
---
.eslintrc.js | 2 ++
libs/horizon/src/renderer/TreeBuilder.ts | 2 +-
libs/horizon/src/renderer/hooks/BaseHook.ts | 8 ++++----
libs/horizon/src/renderer/hooks/HookMain.ts | 18 +++++++++---------
libs/horizon/src/renderer/hooks/HookStage.ts | 2 +-
package.json | 1 +
6 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/.eslintrc.js b/.eslintrc.js
index 46239631..f25357b3 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -32,6 +32,8 @@ module.exports = {
es6: true,
},
rules: {
+ '@typescript-eslint/no-explicit-any': 'off',
+ '@typescript-eslint/no-non-null-assertion': 'off',
'accessor-pairs': 'off',
'brace-style': ['error', '1tbs'],
'func-style': ['warn', 'declaration', { allowArrowFunctions: true }],
diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts
index 721bbff6..ec86db16 100644
--- a/libs/horizon/src/renderer/TreeBuilder.ts
+++ b/libs/horizon/src/renderer/TreeBuilder.ts
@@ -165,7 +165,7 @@ function getChildByIndex(vNode: VNode, idx: number) {
// 从多个更新节点中,计算出开始节点。即:找到最近的共同的父辈节点
export function calcStartUpdateVNode(treeRoot: VNode) {
- const toUpdateNodes = Array.from(treeRoot.toUpdateNodes);
+ const toUpdateNodes = [...treeRoot.toUpdateNodes];
if (toUpdateNodes.length === 0) {
return treeRoot;
diff --git a/libs/horizon/src/renderer/hooks/BaseHook.ts b/libs/horizon/src/renderer/hooks/BaseHook.ts
index 8c3f3605..54e180c8 100644
--- a/libs/horizon/src/renderer/hooks/BaseHook.ts
+++ b/libs/horizon/src/renderer/hooks/BaseHook.ts
@@ -1,7 +1,7 @@
import type { VNode } from '../Types';
import type { Hook } from './HookType';
-let processingVNode: VNode = null;
+let processingVNode: VNode | null = null;
// lastTimeHook是上一次执行func时产生的hooks中,与currentHook对应的hook
let lastTimeHook: Hook | null = null;
@@ -13,7 +13,7 @@ export function getProcessingVNode() {
return processingVNode;
}
-export function setProcessingVNode(vNode: VNode) {
+export function setProcessingVNode(vNode: VNode | null) {
processingVNode = vNode;
}
@@ -21,11 +21,11 @@ export function getLastTimeHook() {
return lastTimeHook;
}
-export function setLastTimeHook(hook: Hook) {
+export function setLastTimeHook(hook: Hook | null) {
lastTimeHook = hook;
}
-export function setCurrentHook(hook: Hook) {
+export function setCurrentHook(hook: Hook | null) {
currentHook = hook;
}
diff --git a/libs/horizon/src/renderer/hooks/HookMain.ts b/libs/horizon/src/renderer/hooks/HookMain.ts
index e8992e5a..f4c568ea 100644
--- a/libs/horizon/src/renderer/hooks/HookMain.ts
+++ b/libs/horizon/src/renderer/hooks/HookMain.ts
@@ -15,17 +15,17 @@ import {
setProcessingVNode,
setCurrentHook, getNextHook
} from './BaseHook';
-import {useStateImpl,} from './UseStateHook';
-import {useReducerImpl,} from './UseReducerHook';
+import {useStateImpl} from './UseStateHook';
+import {useReducerImpl} from './UseReducerHook';
import {HookStage, setHookStage} from './HookStage';
// hook对外入口
-export function exeFunctionHook(
- funcComp: (props: Object, arg: Object) => any,
- props: Object,
- arg: Object,
+export function exeFunctionHook, Arg>(
+ funcComp: (props: Props, arg: Arg) => any,
+ props: Props,
+ arg: Arg,
processing: VNode,
-): any {
+) {
// 重置全局变量
resetGlobalVariable();
@@ -39,13 +39,13 @@ export function exeFunctionHook(
processing.effectList = [];
// 设置hook阶段
- if (processing.isCreated || !processing.oldHooks.length) {
+ if (processing.isCreated || !processing.oldHooks!.length) {
setHookStage(HookStage.Init);
} else {
setHookStage(HookStage.Update);
}
- let comp = funcComp(props, arg);
+ const comp = funcComp(props, arg);
// 设置hook阶段为null,用于判断hook是否在函数组件中调用
setHookStage(null);
diff --git a/libs/horizon/src/renderer/hooks/HookStage.ts b/libs/horizon/src/renderer/hooks/HookStage.ts
index c3e9622a..4819554d 100644
--- a/libs/horizon/src/renderer/hooks/HookStage.ts
+++ b/libs/horizon/src/renderer/hooks/HookStage.ts
@@ -10,6 +10,6 @@ export function getHookStage() {
return hookStage;
}
-export function setHookStage(phase: HookStage) {
+export function setHookStage(phase: HookStage| null) {
hookStage = phase;
}
diff --git a/package.json b/package.json
index d3da90aa..5ef9d520 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,7 @@
"libs/*"
],
"scripts": {
+ "lint": "eslint . --ext .ts",
"build": " webpack --config ./scripts/webpack/webpack.config.js",
"build-3rdLib": "node ./scripts/gen3rdLib.js",
"build-3rdLib-dev": "npm run build & node ./scripts/gen3rdLib.js --dev",
From 35d98b615fd7556907ffc40dee40e31fbf2089fd Mon Sep 17 00:00:00 2001
From: * <8>
Date: Thu, 24 Mar 2022 11:56:57 +0800
Subject: [PATCH 06/13] Match-id-18f59c81b8302ce98bbefcf4608d9327523dd34b
---
libs/horizon/src/renderer/TreeBuilder.ts | 2 +-
.../src/renderer/render/ClsOrFunComponent.ts | 36 -------------------
libs/horizon/src/renderer/render/index.ts | 3 --
libs/horizon/src/renderer/vnode/VNode.ts | 21 +++++------
.../src/renderer/vnode/VNodeCreator.ts | 10 +++---
libs/horizon/src/renderer/vnode/VNodeTags.ts | 1 -
6 files changed, 14 insertions(+), 59 deletions(-)
delete mode 100644 libs/horizon/src/renderer/render/ClsOrFunComponent.ts
diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts
index ec86db16..721bbff6 100644
--- a/libs/horizon/src/renderer/TreeBuilder.ts
+++ b/libs/horizon/src/renderer/TreeBuilder.ts
@@ -165,7 +165,7 @@ function getChildByIndex(vNode: VNode, idx: number) {
// 从多个更新节点中,计算出开始节点。即:找到最近的共同的父辈节点
export function calcStartUpdateVNode(treeRoot: VNode) {
- const toUpdateNodes = [...treeRoot.toUpdateNodes];
+ const toUpdateNodes = Array.from(treeRoot.toUpdateNodes);
if (toUpdateNodes.length === 0) {
return treeRoot;
diff --git a/libs/horizon/src/renderer/render/ClsOrFunComponent.ts b/libs/horizon/src/renderer/render/ClsOrFunComponent.ts
deleted file mode 100644
index fd342fac..00000000
--- a/libs/horizon/src/renderer/render/ClsOrFunComponent.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import type {VNode} from '../Types';
-
-import {FunctionComponent} from '../vnode/VNodeTags';
-import {resetDepContexts} from '../components/context/Context';
-import {getOldContext} from '../components/context/CompatibleContext';
-import {FlagUtils} from '../vnode/VNodeFlags';
-import {exeFunctionHook} from '../hooks/HookMain';
-import { createChildrenByDiff } from '../diff/nodeDiffComparator';
-
-function captureIndeterminateComponent(
- processing: VNode,
-): VNode | null {
- const funcComp = processing.type;
-
- if (!processing.isCreated) {
- processing.isCreated = true;
- FlagUtils.markAddition(processing);
- }
-
- const props = processing.props;
- const context = getOldContext(processing, funcComp, false);
-
- resetDepContexts(processing);
-
- const newElements = exeFunctionHook(funcComp, props, context, processing);
-
- processing.tag = FunctionComponent;
- processing.child = createChildrenByDiff(processing, processing.child, newElements, !processing.isCreated);
- return processing.child;
-}
-
-export function captureRender(processing: VNode): VNode | null {
- return captureIndeterminateComponent(processing);
-}
-
-export function bubbleRender() {}
diff --git a/libs/horizon/src/renderer/render/index.ts b/libs/horizon/src/renderer/render/index.ts
index 29637aa3..4497627a 100644
--- a/libs/horizon/src/renderer/render/index.ts
+++ b/libs/horizon/src/renderer/render/index.ts
@@ -10,7 +10,6 @@ import * as DomPortalRender from './DomPortal';
import * as TreeRootRender from './TreeRoot';
import * as DomTextRender from './DomText';
import * as IncompleteClassComponentRender from './IncompleteClassComponent';
-import * as ClsOrFunComponentRender from './ClsOrFunComponent';
import * as LazyComponentRender from './LazyComponent';
import * as MemoComponentRender from './MemoComponent';
import * as SuspenseComponentRender from './SuspenseComponent';
@@ -27,7 +26,6 @@ import {
TreeRoot,
DomText,
IncompleteClassComponent,
- ClsOrFunComponent,
LazyComponent,
MemoComponent,
SuspenseComponent,
@@ -49,7 +47,6 @@ export default {
[TreeRoot]: TreeRootRender,
[DomText]: DomTextRender,
[IncompleteClassComponent]: IncompleteClassComponentRender,
- [ClsOrFunComponent]: ClsOrFunComponentRender,
[LazyComponent]: LazyComponentRender,
[MemoComponent]: MemoComponentRender,
[SuspenseComponent]: SuspenseComponentRender,
diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts
index b076a3eb..6386fd98 100644
--- a/libs/horizon/src/renderer/vnode/VNode.ts
+++ b/libs/horizon/src/renderer/vnode/VNode.ts
@@ -1,7 +1,7 @@
/**
* 虚拟DOM结构体
*/
-import { TreeRoot, FunctionComponent, ClassComponent, DomPortal, DomText, ContextConsumer, ForwardRef, SuspenseComponent, LazyComponent, ClsOrFunComponent, DomComponent, Fragment, ContextProvider, Profiler, MemoComponent, IncompleteClassComponent } from './VNodeTags';
+import { TreeRoot, FunctionComponent, ClassComponent, DomPortal, DomText, ContextConsumer, ForwardRef, SuspenseComponent, LazyComponent, DomComponent, Fragment, ContextProvider, Profiler, MemoComponent, IncompleteClassComponent } from './VNodeTags';
import type { VNodeTag } from './VNodeTags';
import type { RefType, ContextType } from '../Types';
import type { Hook } from '../hooks/HookType';
@@ -18,8 +18,8 @@ export class VNode {
parent: VNode | null = null; // 父节点
child: VNode | null = null; // 子节点
next: VNode | null = null; // 兄弟节点
- cIndex: number = 0; // 节点在children数组中的位置
- eIndex: number = 0; // HorizonElement在jsx中的位置,例如:jsx中的null不会生成vNode,所以eIndex和cIndex不一致
+ cIndex = 0; // 节点在children数组中的位置
+ eIndex = 0; // HorizonElement在jsx中的位置,例如:jsx中的null不会生成vNode,所以eIndex和cIndex不一致
ref: RefType | ((handle: any) => void) | null = null; // 包裹一个函数,submit阶段使用,比如将外部useRef生成的对象赋值到ref上
oldProps: any = null;
@@ -33,12 +33,12 @@ export class VNode {
state: any; // ClassComponent和TreeRoot的状态
hooks: Array> | null; // 保存hook
- suspenseChildStatus: string = ''; // Suspense的Children是否显示
+ suspenseChildStatus = ''; // Suspense的Children是否显示
depContexts: Array> | null; // FunctionComponent和ClassComponent对context的依赖列表
isDepContextChange: boolean; // context是否变更
dirtyNodes: Array | null = null; // 需要改动的节点数组
- shouldUpdate: boolean = false;
- childShouldUpdate: boolean = false;
+ shouldUpdate = false;
+ childShouldUpdate = false;
task: any;
// 使用这个变量来记录修改前的值,用于恢复。
@@ -51,7 +51,7 @@ export class VNode {
flags = InitFlag;
clearChild: VNode | null;
// one tree相关属性
- isCreated: boolean = true;
+ isCreated = true;
oldHooks: Array> | null; // 保存上一次执行的hook
oldState: any;
oldRef: RefType | ((handle: any) => void) | null = null;
@@ -61,7 +61,7 @@ export class VNode {
suspenseDidCapture: boolean; // suspense是否捕获了异常
promiseResolve: boolean; // suspense的promise是否resolve
- path: string = ''; // 保存从根到本节点的路径
+ path = ''; // 保存从根到本节点的路径
toUpdateNodes: Set | null; // 保存要更新的节点
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用
@@ -84,6 +84,7 @@ export class VNode {
this.contexts = null;
break;
case FunctionComponent:
+ this.realNode = null;
this.effectList = null;
this.hooks = null;
this.depContexts = null;
@@ -101,10 +102,6 @@ export class VNode {
this.oldState = null;
this.contexts = null;
break;
- case ClsOrFunComponent:
- this.realNode = null;
- this.contexts = null;
- break;
case DomPortal:
this.realNode = null;
this.contexts = null;
diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts
index 8c76d63c..5dc4ccac 100644
--- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts
+++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts
@@ -11,7 +11,6 @@ import {
DomPortal,
TreeRoot,
DomText,
- ClsOrFunComponent,
LazyComponent,
MemoComponent,
SuspenseComponent,
@@ -52,13 +51,12 @@ function isClassComponent(comp: Function) {
// 解析懒组件的tag
export function getLazyVNodeTag(lazyComp: any): string {
- let vNodeTag = ClsOrFunComponent;
if (typeof lazyComp === 'function') {
- vNodeTag = isClassComponent(lazyComp) ? ClassComponent : FunctionComponent;
+ return isClassComponent(lazyComp) ? ClassComponent : FunctionComponent;
} else if (lazyComp !== undefined && lazyComp !== null && typeLazyMap[lazyComp.vtype]) {
- vNodeTag = typeLazyMap[lazyComp.vtype];
+ return typeLazyMap[lazyComp.vtype];
}
- return vNodeTag;
+ throw Error("Horizon can't resolve the content of lazy ")
}
// 创建processing
@@ -105,7 +103,7 @@ export function createPortalVNode(portal) {
}
export function createUndeterminedVNode(type, key, props) {
- let vNodeTag = ClsOrFunComponent;
+ let vNodeTag = FunctionComponent;
let isLazy = false;
const componentType = typeof type;
diff --git a/libs/horizon/src/renderer/vnode/VNodeTags.ts b/libs/horizon/src/renderer/vnode/VNodeTags.ts
index 2ec1db13..6e02e450 100644
--- a/libs/horizon/src/renderer/vnode/VNodeTags.ts
+++ b/libs/horizon/src/renderer/vnode/VNodeTags.ts
@@ -6,7 +6,6 @@ export type VNodeTag = string;
export const TreeRoot = 'TreeRoot'; // tree的根节点,用于存放一些tree级的变量
export const FunctionComponent = 'FunctionComponent';
export const ClassComponent = 'ClassComponent';
-export const ClsOrFunComponent = 'ClsOrFunComponent';
export const DomPortal = 'DomPortal';
export const DomComponent = 'DomComponent';
export const DomText = 'DomText';
From 78054d047a5ea02d1ed392235b5df64e2ceadef7 Mon Sep 17 00:00:00 2001
From: * <8>
Date: Thu, 24 Mar 2022 15:50:28 +0800
Subject: [PATCH 07/13] Match-id-fd102dce95197e4779d6b0155b78e27fa1b8a95e
---
libs/horizon/src/renderer/hooks/HookStage.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libs/horizon/src/renderer/hooks/HookStage.ts b/libs/horizon/src/renderer/hooks/HookStage.ts
index 4819554d..5f0a5a65 100644
--- a/libs/horizon/src/renderer/hooks/HookStage.ts
+++ b/libs/horizon/src/renderer/hooks/HookStage.ts
@@ -10,6 +10,6 @@ export function getHookStage() {
return hookStage;
}
-export function setHookStage(phase: HookStage| null) {
+export function setHookStage(phase: HookStage | null) {
hookStage = phase;
}
From c5dbb91635bb801682532ddc3b5b618b606e6750 Mon Sep 17 00:00:00 2001
From: * <8>
Date: Thu, 24 Mar 2022 16:04:38 +0800
Subject: [PATCH 08/13] Match-id-a41469cf2ad241a94d6f75a6753fd7af282d1453
---
.eslintrc.js | 1 +
libs/horizon/src/renderer/vnode/VNodeCreator.ts | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/.eslintrc.js b/.eslintrc.js
index f25357b3..1a425fc3 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -34,6 +34,7 @@ module.exports = {
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
+ 'semi': ["error", "always"],
'accessor-pairs': 'off',
'brace-style': ['error', '1tbs'],
'func-style': ['warn', 'declaration', { allowArrowFunctions: true }],
diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts
index 5dc4ccac..457a1000 100644
--- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts
+++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts
@@ -56,7 +56,7 @@ export function getLazyVNodeTag(lazyComp: any): string {
} else if (lazyComp !== undefined && lazyComp !== null && typeLazyMap[lazyComp.vtype]) {
return typeLazyMap[lazyComp.vtype];
}
- throw Error("Horizon can't resolve the content of lazy ")
+ throw Error("Horizon can't resolve the content of lazy ");
}
// 创建processing
From a4f376b84b5edb70e937333fe376633822106558 Mon Sep 17 00:00:00 2001
From: * <8>
Date: Thu, 24 Mar 2022 16:08:18 +0800
Subject: [PATCH 09/13] Match-id-a2ff0c3642c1fb4b11d6b634a3fba736bf98d405
---
.eslintrc.js | 3 ++-
libs/horizon/src/renderer/vnode/VNodeCreator.ts | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/.eslintrc.js b/.eslintrc.js
index 1a425fc3..ab410fd1 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -34,7 +34,8 @@ module.exports = {
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
- 'semi': ["error", "always"],
+ 'semi': ['warn', 'always'],
+ 'quotes': ['warn', 'single'],
'accessor-pairs': 'off',
'brace-style': ['error', '1tbs'],
'func-style': ['warn', 'declaration', { allowArrowFunctions: true }],
diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts
index 457a1000..9a677f53 100644
--- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts
+++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts
@@ -56,7 +56,7 @@ export function getLazyVNodeTag(lazyComp: any): string {
} else if (lazyComp !== undefined && lazyComp !== null && typeLazyMap[lazyComp.vtype]) {
return typeLazyMap[lazyComp.vtype];
}
- throw Error("Horizon can't resolve the content of lazy ");
+ throw Error('Horizon can\'t resolve the content of lazy');
}
// 创建processing
From a3c5839a6b4b3d77231f49457200436e3fcd2fa1 Mon Sep 17 00:00:00 2001
From: * <8>
Date: Fri, 25 Mar 2022 18:28:35 +0800
Subject: [PATCH 10/13] Match-id-b83bfbcd95720511a7e584ab7beb932978e800e2
---
scripts/__tests__/EventTest/EventMain.test.js | 131 +++++++++++++
.../__tests__/EventTest/FocusEvent.test.js | 46 +++++
.../__tests__/EventTest/KeyboardEvent.test.js | 179 ++++++++++++++++++
.../__tests__/EventTest/MouseEvent.test.js | 160 ++++++++++++++++
.../__tests__/EventTest/WheelEvent.test.js | 52 +++++
scripts/__tests__/jest/testUtils.js | 26 +++
6 files changed, 594 insertions(+)
create mode 100644 scripts/__tests__/EventTest/EventMain.test.js
create mode 100644 scripts/__tests__/EventTest/FocusEvent.test.js
create mode 100644 scripts/__tests__/EventTest/KeyboardEvent.test.js
create mode 100644 scripts/__tests__/EventTest/MouseEvent.test.js
create mode 100644 scripts/__tests__/EventTest/WheelEvent.test.js
create mode 100644 scripts/__tests__/jest/testUtils.js
diff --git a/scripts/__tests__/EventTest/EventMain.test.js b/scripts/__tests__/EventTest/EventMain.test.js
new file mode 100644
index 00000000..1a3291c5
--- /dev/null
+++ b/scripts/__tests__/EventTest/EventMain.test.js
@@ -0,0 +1,131 @@
+import * as Horizon from '@cloudsop/horizon/index.ts';
+import * as LogUtils from '../jest/logUtils';
+import * as TestUtils from '../jest/testUtils';
+
+describe('事件', () => {
+ it('根节点挂载全量事件', () => {
+ const App = () => {
+ return ;
+ }
+ Horizon.render(, container);
+ console.log(TestUtils.getEventListeners(container));
+ })
+
+ it('事件捕获与冒泡', () => {
+ const App = () => {
+ return (
+ <>
+ LogUtils.log('div capture')} onClick={() => LogUtils.log('div bubble')}>
+
LogUtils.log('p capture')} onClick={() => LogUtils.log('p bubble')}>
+
+
+ >
+ );
+ }
+ Horizon.render(, container);
+ const a = container.querySelector('button');
+ a.click();
+ expect(LogUtils.getAndClear()).toEqual([
+ // 从外到内先捕获再冒泡
+ 'div capture',
+ 'p capture',
+ 'btn capture',
+ 'btn bubble',
+ 'p bubble',
+ 'div bubble'
+ ]);
+ })
+
+ it('returns 0', () => {
+ let keyCode = null;
+ const node = Horizon.render(
+ {
+ keyCode = e.keyCode;
+ }}
+ />,
+ container,
+ );
+ node.dispatchEvent(
+ new KeyboardEvent('keypress', {
+ keyCode: 65,
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+ expect(keyCode).toBe(65);
+ });
+
+ it('阻止事件冒泡', () => {
+ const App = () => {
+ return (
+ <>
+ LogUtils.log('div capture')} onClick={() => LogUtils.log('div bubble')}>
+
LogUtils.log('p capture')} onClick={() => LogUtils.log('p bubble')}>
+
+
+ >
+ );
+ }
+ Horizon.render(, container);
+ container.querySelector('button').click();
+
+ expect(LogUtils.getAndClear()).toEqual([
+ // 到button时停止冒泡
+ 'div capture',
+ 'p capture',
+ 'btn capture',
+ 'btn bubble'
+ ]);
+ })
+
+ it('阻止事件捕获', () => {
+ const App = () => {
+ return (
+ <>
+ TestUtils.stopBubbleOrCapture(e, 'div capture')} onClick={() => LogUtils.log('div bubble')}>
+
LogUtils.log('p capture')} onClick={() => LogUtils.log('p bubble')}>
+
+
+ >
+ );
+ }
+ Horizon.render(, container);
+ container.querySelector('button').click();
+
+ expect(LogUtils.getAndClear()).toEqual([
+ // 阻止捕获,不再继续向下执行
+ 'div capture'
+ ]);
+ })
+
+ it('阻止原生事件冒泡', () => {
+ const App = () => {
+ return (
+
+ );
+ }
+ Horizon.render(, container);
+ container.querySelector('div').addEventListener('click', () => {
+ LogUtils.log('div bubble');
+ }, false);
+ container.querySelector('p').addEventListener('click', () => {
+ LogUtils.log('p bubble');
+ }, false);
+ container.querySelector('button').addEventListener('click', (e) => {
+ LogUtils.log('btn bubble');
+ e.stopPropagation();
+ }, false);
+ container.querySelector('button').click();
+ expect(LogUtils.getAndClear()).toEqual([
+ 'btn bubble'
+ ]);
+ })
+})
diff --git a/scripts/__tests__/EventTest/FocusEvent.test.js b/scripts/__tests__/EventTest/FocusEvent.test.js
new file mode 100644
index 00000000..ee5e3c46
--- /dev/null
+++ b/scripts/__tests__/EventTest/FocusEvent.test.js
@@ -0,0 +1,46 @@
+import * as Horizon from '@cloudsop/horizon/index.ts';
+import * as LogUtils from '../jest/logUtils';
+import { act } from '../jest/customMatcher';
+
+describe('合成焦点事件', () => {
+
+ it('onFocus', () => {
+ const realNode = Horizon.render(
+ LogUtils.log(`onFocus: ${event.type}`)}
+ onFocusCapture={event => LogUtils.log(`onFocusCapture: ${event.type}`)}
+ />, container);
+
+ realNode.dispatchEvent(
+ new FocusEvent('focusin', {
+ bubbles: true,
+ cancelable: false,
+ }),
+ );
+
+ expect(LogUtils.getAndClear()).toEqual([
+ 'onFocusCapture: focus',
+ 'onFocus: focus',
+ ]);
+ });
+
+ it('onBlur', () => {
+ const realNode = Horizon.render(
+ LogUtils.log(`onBlur: ${event.type}`)}
+ onBlurCapture={event => LogUtils.log(`onBlurCapture: ${event.type}`)}
+ />, container);
+
+ realNode.dispatchEvent(
+ new FocusEvent('focusout', {
+ bubbles: true,
+ cancelable: false,
+ }),
+ );
+
+ expect(LogUtils.getAndClear()).toEqual([
+ 'onBlurCapture: blur',
+ 'onBlur: blur',
+ ]);
+ })
+})
\ No newline at end of file
diff --git a/scripts/__tests__/EventTest/KeyboardEvent.test.js b/scripts/__tests__/EventTest/KeyboardEvent.test.js
new file mode 100644
index 00000000..519cc9ce
--- /dev/null
+++ b/scripts/__tests__/EventTest/KeyboardEvent.test.js
@@ -0,0 +1,179 @@
+import * as Horizon from '@cloudsop/horizon/index.ts';
+import * as LogUtils from '../jest/logUtils';
+
+describe('Keyboard Event', () => {
+
+ it('keydown,keypress,keyup的keycode,charcode', () => {
+ const node = Horizon.render(
+ {
+ LogUtils.log('onKeyUp: keycode: ' + e.keyCode + ',charcode: ' + e.charCode);
+ }}
+ onKeyDown={(e) => {
+ LogUtils.log('onKeyDown: keycode: ' + e.keyCode + ',charcode: ' + e.charCode)
+ }}
+ />,
+ container,
+ );
+ node.dispatchEvent(
+ new KeyboardEvent('keydown', {
+ keyCode: 50,
+ code: 'Digit2',
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+ node.dispatchEvent(
+ new KeyboardEvent('keyup', {
+ keyCode: 50,
+ code: 'Digit2',
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+
+ expect(LogUtils.getAndClear()).toEqual([
+ 'onKeyDown: keycode: 50,charcode: 0',
+ 'onKeyUp: keycode: 50,charcode: 0'
+ ]);
+ });
+
+ it('keypress的keycode,charcode', () => {
+ const node = Horizon.render(
+ {
+ LogUtils.log('onKeyPress: keycode: ' + e.keyCode + ',charcode: ' + e.charCode);
+ }}
+ />,
+ container,
+ );
+ node.dispatchEvent(
+ new KeyboardEvent('keypress', {
+ charCode: 50,
+ code: 'Digit2',
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+
+ expect(LogUtils.getAndClear()).toEqual([
+ 'onKeyPress: keycode: 0,charcode: 50'
+ ]);
+ });
+
+ it('当charcode为13,且不设置keycode的时候', () => {
+ const node = Horizon.render(
+ {
+ LogUtils.log('onKeyPress: keycode: ' + e.keyCode + ',charcode: ' + e.charCode);
+ }}
+ />,
+ container,
+ );
+ node.dispatchEvent(
+ new KeyboardEvent('keypress', {
+ charCode: 13,
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+ expect(LogUtils.getAndClear()).toEqual([
+ 'onKeyPress: keycode: 0,charcode: 13'
+ ]);
+ });
+
+ it('keydown,keypress,keyup的code', () => {
+ const node = Horizon.render(
+ {
+ LogUtils.log('onKeyUp: code: ' + e.code);
+ }}
+ onKeyPress={(e) => {
+ LogUtils.log('onKeyPress: code: ' + e.code);
+ }}
+ onKeyDown={(e) => {
+ LogUtils.log('onKeyDown: code: ' + e.code);
+ }}
+ />,
+ container,
+ );
+ node.dispatchEvent(
+ new KeyboardEvent('keydown', {
+ code: 'Digit2',
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+
+ node.dispatchEvent(
+ new KeyboardEvent('keypress', {
+ keyCode: 50,
+ code: 'Digit2',
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+
+ node.dispatchEvent(
+ new KeyboardEvent('keyup', {
+ code: 'Digit2',
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+
+ expect(LogUtils.getAndClear()).toEqual([
+ 'onKeyDown: code: Digit2',
+ 'onKeyPress: code: Digit2',
+ 'onKeyUp: code: Digit2'
+ ]);
+ });
+
+ it('可以执行preventDefault和 stopPropagation', () => {
+ const keyboardProcessing = e => {
+ expect(e.isDefaultPrevented()).toBe(false);
+ e.preventDefault();
+ expect(e.isDefaultPrevented()).toBe(true);
+
+ expect(e.isPropagationStopped()).toBe(false);
+ e.stopPropagation();
+ expect(e.isPropagationStopped()).toBe(true);
+ LogUtils.log(e.type + ' handle');
+ };
+ const div = Horizon.render(
+ ,
+ container,
+ );
+
+ div.dispatchEvent(
+ new KeyboardEvent('keydown', {
+ keyCode: 40,
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+ div.dispatchEvent(
+ new KeyboardEvent('keyup', {
+ keyCode: 40,
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+ div.dispatchEvent(
+ new KeyboardEvent('keypress', {
+ charCode: 40,
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+ expect(LogUtils.getAndClear()).toEqual([
+ 'keydown handle',
+ 'keyup handle',
+ 'keypress handle'
+ ]);
+ });
+});
diff --git a/scripts/__tests__/EventTest/MouseEvent.test.js b/scripts/__tests__/EventTest/MouseEvent.test.js
new file mode 100644
index 00000000..e5ffbae1
--- /dev/null
+++ b/scripts/__tests__/EventTest/MouseEvent.test.js
@@ -0,0 +1,160 @@
+import * as Horizon from '@cloudsop/horizon/index.ts';
+import * as LogUtils from '../jest/logUtils';
+
+describe('MouseEvent Test', () => {
+ describe('onClick Test', () => {
+ it('绑定this', () => {
+ class App extends Horizon.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ num: this.props.num,
+ price: this.props.price
+ };
+ }
+
+ setNum() {
+ this.setState(
+ {
+ num: this.state.num + 1
+ }
+ )
+ }
+
+ setPrice = (e) => {
+ this.setState(
+ {
+ num: this.state.price + 1
+ }
+ )
+ }
+
+ render() {
+ return (
+ <>
+ {this.state.num}
+ {this.state.price}
+
+
+ >
+ );
+ }
+ }
+ Horizon.render(, container);
+ expect(container.querySelector('p').innerHTML).toBe('0');
+ expect(container.querySelector('#p').innerHTML).toBe('100');
+ // 点击按钮触发num加1
+ container.querySelector('button').click();
+ expect(container.querySelector('p').innerHTML).toBe('1');
+
+ container.querySelector('#btn').click();
+ expect(container.querySelector('p').innerHTML).toBe('101');
+ });
+
+ it('点击触发', () => {
+ const handleClick = jest.fn();
+ Horizon.render(, container)
+ container.querySelector('button').click();
+ expect(handleClick).toHaveBeenCalledTimes(1);
+ for (let i = 0; i < 5; i++) {
+ container.querySelector('button').click();
+ }
+ expect(handleClick).toHaveBeenCalledTimes(6);
+ })
+ })
+
+ const test = (name, config) => {
+ const node = Horizon.render(config, container);
+ let event = new MouseEvent(name, {
+ relatedTarget: null,
+ bubbles: true,
+ screenX: 1
+ });
+ node.dispatchEvent(event);
+
+ expect(LogUtils.getAndClear()).toEqual([
+ `${name} capture`,
+ `${name} bubble`
+ ]);
+
+ event = new MouseEvent(name, {
+ relatedTarget: null,
+ bubbles: true,
+ screenX: 2
+ });
+ node.dispatchEvent(event);
+
+ // 再次触发新事件
+ expect(LogUtils.getAndClear()).toEqual([
+ `${name} capture`,
+ `${name} bubble`
+ ]);
+ }
+
+ describe('合成鼠标事件', () => {
+ it('onMouseMove', () => {
+ const onMouseMove = () => {
+ LogUtils.log('mousemove bubble');
+ };
+ const onMouseMoveCapture = () => {
+ LogUtils.log('mousemove capture');
+ };
+ test('mousemove', )
+ });
+
+ it('onMouseDown', () => {
+ const onMousedown = () => {
+ LogUtils.log('mousedown bubble');
+ };
+ const onMousedownCapture = () => {
+ LogUtils.log('mousedown capture');
+ };
+ test('mousedown', )
+ });
+
+ it('onMouseUp', () => {
+ const onMouseUp = () => {
+ LogUtils.log('mouseup bubble');
+ };
+ const onMouseUpCapture = () => {
+ LogUtils.log('mouseup capture');
+ };
+ test('mouseup', )
+ });
+
+ it('onMouseOut', () => {
+ const onMouseOut = () => {
+ LogUtils.log('mouseout bubble');
+ };
+ const onMouseOutCapture = () => {
+ LogUtils.log('mouseout capture');
+ };
+ test('mouseout', )
+ });
+
+ it('onMouseOver', () => {
+ const onMouseOver = () => {
+ LogUtils.log('mouseover bubble');
+ };
+ const onMouseOverCapture = () => {
+ LogUtils.log('mouseover capture');
+ };
+ test('mouseover', )
+ });
+ })
+})
diff --git a/scripts/__tests__/EventTest/WheelEvent.test.js b/scripts/__tests__/EventTest/WheelEvent.test.js
new file mode 100644
index 00000000..a0ebf933
--- /dev/null
+++ b/scripts/__tests__/EventTest/WheelEvent.test.js
@@ -0,0 +1,52 @@
+import * as Horizon from '@cloudsop/horizon/index.ts';
+import * as LogUtils from '../jest/logUtils';
+
+describe('合成滚轮事件', () => {
+ it('onWheel', () => {
+ const realNode = Horizon.render(
+ LogUtils.log(`onWheel: ${event.type}`)}
+ onWheelCapture={event => LogUtils.log(`onWheelCapture: ${event.type}`)}
+ />, container);
+
+ realNode.dispatchEvent(
+ new MouseEvent('wheel', {
+ bubbles: true,
+ cancelable: false,
+ }),
+ );
+
+ expect(LogUtils.getAndClear()).toEqual([
+ 'onWheelCapture: wheel',
+ 'onWheel: wheel'
+ ]);
+ });
+
+ it('可以执行preventDefault和 stopPropagation', () => {
+ const eventHandler = e => {
+ expect(e.isDefaultPrevented()).toBe(false);
+ e.preventDefault();
+ expect(e.isDefaultPrevented()).toBe(true);
+
+ expect(e.isPropagationStopped()).toBe(false);
+ e.stopPropagation();
+ expect(e.isPropagationStopped()).toBe(true);
+ LogUtils.log(e.type + ' handle');
+ };
+ const realNode = Horizon.render(
+
,
+ container
+ );
+
+ realNode.dispatchEvent(
+ new MouseEvent('wheel', {
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
+ expect(LogUtils.getAndClear()).toEqual([
+ 'wheel handle'
+ ]);
+ });
+
+})
\ No newline at end of file
diff --git a/scripts/__tests__/jest/testUtils.js b/scripts/__tests__/jest/testUtils.js
new file mode 100644
index 00000000..8bab93d9
--- /dev/null
+++ b/scripts/__tests__/jest/testUtils.js
@@ -0,0 +1,26 @@
+import { allDelegatedNativeEvents } from '../../../libs/horizon/src/event/EventCollection';
+import * as LogUtils from './logUtils';
+
+export const stopBubbleOrCapture = (e, value) => {
+ LogUtils.log(value)
+ e.stopPropagation();
+};
+
+export const getEventListeners = (dom) => {
+ let ret = true
+ let keyArray = [];
+ for (var key in dom) {
+ keyArray.push(key);
+ }
+ try {
+ allDelegatedNativeEvents.forEach(event => {
+ if (!keyArray.includes(event)) {
+ ret = false;
+ throw new Error('没有挂载全量事件');
+ }
+ })
+ } catch (error) {
+
+ }
+ return ret;
+};
\ No newline at end of file
From 867cb48365e5fd88cbe488d8040b6e178b98e40d Mon Sep 17 00:00:00 2001
From: * <8>
Date: Mon, 28 Mar 2022 20:10:21 +0800
Subject: [PATCH 11/13] Match-id-2a7374e4246145afb0681f473ee89cd06e492eb7
---
libs/horizon/src/renderer/ContextSaver.ts | 68 ++----------
.../components/context/CompatibleContext.ts | 101 ------------------
.../src/renderer/render/BaseComponent.ts | 7 --
.../src/renderer/render/ClassComponent.ts | 27 +----
.../src/renderer/render/FunctionComponent.ts | 8 +-
.../render/IncompleteClassComponent.ts | 16 +--
.../src/renderer/render/SuspenseComponent.ts | 2 +
libs/horizon/src/renderer/render/TreeRoot.ts | 2 -
libs/horizon/src/renderer/vnode/VNodeFlags.ts | 1 +
9 files changed, 16 insertions(+), 216 deletions(-)
delete mode 100644 libs/horizon/src/renderer/components/context/CompatibleContext.ts
diff --git a/libs/horizon/src/renderer/ContextSaver.ts b/libs/horizon/src/renderer/ContextSaver.ts
index 62586895..ef243cce 100644
--- a/libs/horizon/src/renderer/ContextSaver.ts
+++ b/libs/horizon/src/renderer/ContextSaver.ts
@@ -3,11 +3,11 @@
* 在深度遍历过程中,begin阶段会修改一些全局的值,在complete阶段会恢复。
*/
-import type {VNode, ContextType} from './Types';
-import type {Container} from '../dom/DOMOperator';
+import type { VNode, ContextType } from './Types';
+import type { Container } from '../dom/DOMOperator';
-import {getNSCtx} from '../dom/DOMOperator';
-import {ContextProvider} from './vnode/VNodeTags';
+import { getNSCtx } from '../dom/DOMOperator';
+import { ContextProvider } from './vnode/VNodeTags';
// 保存的是“http://www.w3.org/1999/xhtml”或“http://www.w3.org/2000/svg”,
// 用于识别是使用document.createElement()还是使用document.createElementNS()创建DOM
@@ -18,16 +18,8 @@ const CTX_CONTEXT = 'CTX_CONTEXT';
// 旧版context API,是否更改。
const CTX_OLD_CHANGE = 'CTX_OLD_CHANGE';
-// 旧版context API,保存的是的当前组件提供给子组件使用的context。
-const CTX_OLD_CONTEXT = 'CTX_OLD_CONTEXT';
-// 旧版context API,保存的是的上一个提供者提供给后代组件使用的context。
-const CTX_OLD_PREVIOUS_CONTEXT = 'CTX_OLD_PREVIOUS_CONTEXT';
-
-let ctxNamespace: string = '';
-
-let ctxOldContext: Object = {};
-let ctxOldChange: Boolean = false;
-let ctxOldPreviousContext: Object = {};
+let ctxOldChange = false;
+let ctxNamespace = '';
function setContext(vNode: VNode, contextName, value) {
if (vNode.contexts === null) {
@@ -38,6 +30,7 @@ function setContext(vNode: VNode, contextName, value) {
vNode.contexts[contextName] = value;
}
}
+
function getContext(vNode: VNode, contextName) {
if (vNode.contexts !== null) {
return vNode.contexts[contextName];
@@ -87,44 +80,6 @@ function recoverParentsContextCtx(vNode: VNode) {
}
}
-// ctxOldContext是 旧context提供者的context
-function setVNodeOldContext(providerVNode: VNode, context: Object) {
- setContext(providerVNode, CTX_OLD_CONTEXT, context);
-}
-
-function getVNodeOldContext(vNode: VNode) {
- return getContext(vNode, CTX_OLD_CONTEXT);
-}
-
-function setOldContextCtx(providerVNode: VNode, context: Object) {
- setVNodeOldContext(providerVNode, context);
- ctxOldContext = context;
-}
-
-function getOldContextCtx() {
- return ctxOldContext;
-}
-
-function resetOldContextCtx(vNode: VNode) {
- ctxOldContext = getVNodeOldContext(vNode);
-}
-
-function setVNodeOldPreviousContext(providerVNode: VNode, context: Object) {
- setContext(providerVNode, CTX_OLD_PREVIOUS_CONTEXT, context);
-}
-
-function getVNodeOldPreviousContext(vNode: VNode) {
- return getContext(vNode, CTX_OLD_PREVIOUS_CONTEXT);
-}
-
-function setOldPreviousContextCtx(context: Object) {
- ctxOldPreviousContext = context;
-}
-
-function getOldPreviousContextCtx() {
- return ctxOldPreviousContext;
-}
-
function setContextChangeCtx(providerVNode: VNode, didChange: boolean) {
setContext(providerVNode, CTX_OLD_CHANGE, didChange);
ctxOldChange = didChange;
@@ -145,18 +100,9 @@ export {
setContextCtx,
resetContextCtx,
recoverParentsContextCtx,
- setOldContextCtx,
- getOldContextCtx,
- resetOldContextCtx,
setContextChangeCtx,
getContextChangeCtx,
resetContextChangeCtx,
- setOldPreviousContextCtx,
- getOldPreviousContextCtx,
- setVNodeOldContext,
- getVNodeOldContext,
- setVNodeOldPreviousContext,
- getVNodeOldPreviousContext,
};
diff --git a/libs/horizon/src/renderer/components/context/CompatibleContext.ts b/libs/horizon/src/renderer/components/context/CompatibleContext.ts
deleted file mode 100644
index 0d6a4bd8..00000000
--- a/libs/horizon/src/renderer/components/context/CompatibleContext.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import type {VNode} from '../../Types';
-
-import {
- setOldContextCtx,
- setContextChangeCtx,
- getOldContextCtx,
- resetOldContextCtx,
- resetContextChangeCtx,
- setOldPreviousContextCtx,
- getOldPreviousContextCtx,
- setVNodeOldContext,
- getVNodeOldContext,
- setVNodeOldPreviousContext,
- getVNodeOldPreviousContext,
-} from '../../ContextSaver';
-
-const emptyObject = {};
-
-// 判断是否是过时的context的提供者
-export function isOldProvider(comp: Function): boolean {
- // @ts-ignore
- const childContextTypes = comp.childContextTypes;
- return childContextTypes !== null && childContextTypes !== undefined;
-}
-
-// 判断是否是过时的context的消费者
-export function isOldConsumer(comp: Function): boolean {
- // @ts-ignore
- const contextTypes = comp.contextTypes;
- return contextTypes !== null && contextTypes !== undefined;
-}
-
-// 如果是旧版context提供者,则缓存两个全局变量,上一个提供者提供的context和当前提供者提供的context
-export function cacheOldCtx(processing: VNode, hasOldContext: any): void {
- // 每一个context提供者都会更新ctxOldContext
- if (hasOldContext) {
- setOldPreviousContextCtx(getOldContextCtx());
-
- const vNodeContext = getVNodeOldContext(processing) || emptyObject;
- setOldContextCtx(processing, vNodeContext);
- }
-}
-
-// 获取当前组件可以消费的context
-export function getOldContext(processing: VNode, clazz: Function, ifProvider: boolean) {
- const type = processing.type;
- // 不是context消费者, 则直接返回空对象
- if (!isOldConsumer(type)) {
- return emptyObject;
- }
-
- // 当组件既是提供者,也是消费者时,取上一个context,不能直接取最新context,因为已经被更新为当前组件的context;
- // 当组件只是消费者时,则取最新context
- const parentContext = (ifProvider && isOldProvider(clazz)) ?
- getOldPreviousContextCtx() :
- getOldContextCtx();
-
- // 除非父级context更改,否则不需要重新创建子context,直接取对应节点上存的。
- if (getVNodeOldPreviousContext(processing) === parentContext) {
- return getVNodeOldContext(processing);
- }
-
- // 从父的context中取出子定义的context
- const context = {};
- for (const key in type.contextTypes) {
- context[key] = parentContext[key];
- }
-
- // 缓存当前组件的context,最近祖先传递下来context,当前可消费的context
- setVNodeOldPreviousContext(processing, parentContext);
- setVNodeOldContext(processing, context);
-
- return context;
-}
-
-// 重置context
-export function resetOldCtx(vNode: VNode): void {
- resetOldContextCtx(vNode);
- resetContextChangeCtx(vNode);
-}
-
-// 当前组件是提供者,则需要合并祖先context和当前组件提供的context
-function handleContext(vNode: VNode, parentContext: Object): Object {
- const instance = vNode.realNode;
-
- if (typeof instance.getChildContext !== 'function') {
- return parentContext;
- }
-
- // 合并祖先提供的context和当前组件提供的context
- return {...parentContext, ...instance.getChildContext()};
-}
-
-// 当前组件是context提供者,更新时,需要合并祖先context和当前组件提供的context
-export function updateOldContext(vNode: VNode): void {
- const ctx = handleContext(vNode, getOldPreviousContextCtx());
- // 更新context,给子组件用的context
- setOldContextCtx(vNode, ctx);
- // 标记更改
- setContextChangeCtx(vNode, true);
-}
diff --git a/libs/horizon/src/renderer/render/BaseComponent.ts b/libs/horizon/src/renderer/render/BaseComponent.ts
index c94d815d..94e5ecf4 100644
--- a/libs/horizon/src/renderer/render/BaseComponent.ts
+++ b/libs/horizon/src/renderer/render/BaseComponent.ts
@@ -1,8 +1,6 @@
import type { VNode } from '../Types';
-import {cacheOldCtx, isOldProvider} from '../components/context/CompatibleContext';
import {
- ClassComponent,
ContextProvider,
DomComponent,
DomPortal,
@@ -23,11 +21,6 @@ function handlerContext(processing: VNode) {
case DomComponent:
setNamespaceCtx(processing);
break;
- case ClassComponent: {
- const isOldCxtExist = isOldProvider(processing.type);
- cacheOldCtx(processing, isOldCxtExist);
- break;
- }
case DomPortal:
setNamespaceCtx(processing, processing.realNode);
break;
diff --git a/libs/horizon/src/renderer/render/ClassComponent.ts b/libs/horizon/src/renderer/render/ClassComponent.ts
index 6db4dcf2..002e343d 100644
--- a/libs/horizon/src/renderer/render/ClassComponent.ts
+++ b/libs/horizon/src/renderer/render/ClassComponent.ts
@@ -2,13 +2,6 @@ import type { VNode } from '../Types';
import { mergeDefaultProps } from './LazyComponent';
import { getNewContext, resetDepContexts } from '../components/context/Context';
-import {
- cacheOldCtx,
- getOldContext,
- isOldProvider,
- resetOldCtx,
- updateOldContext,
-} from '../components/context/CompatibleContext';
import {
callComponentWillMount,
callComponentWillReceiveProps,
@@ -25,17 +18,18 @@ import { markRef } from './BaseComponent';
import {
processUpdates,
} from '../UpdateHandler';
-import { getContextChangeCtx, setContextChangeCtx } from '../ContextSaver';
+import { getContextChangeCtx } from '../ContextSaver';
import { setProcessingClassVNode } from '../GlobalVar';
import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator';
import { createChildrenByDiff } from '../diff/nodeDiffComparator';
+const emptyContextObj = {};
// 获取当前节点的context
export function getCurrentContext(clazz, processing: VNode) {
const context = clazz.contextType;
return typeof context === 'object' && context !== null
? getNewContext(processing, context)
- : getOldContext(processing, clazz, true);
+ : emptyContextObj;
}
// 挂载实例
@@ -112,8 +106,6 @@ export function captureRender(processing: VNode): VNode | null {
clazz = clazz._load(clazz._content);
}
}
- const isOldCxtExist = isOldProvider(clazz);
- cacheOldCtx(processing, isOldCxtExist);
resetDepContexts(processing);
@@ -170,24 +162,13 @@ export function captureRender(processing: VNode): VNode | null {
// 不复用
if (shouldUpdate) {
- // 更新context
- if (isOldCxtExist) {
- updateOldContext(processing);
- }
return createChildren(clazz, processing);
} else {
- if (isOldCxtExist) {
- setContextChangeCtx(processing, false);
- }
return onlyUpdateChildVNodes(processing);
}
}
-export function bubbleRender(processing: VNode) {
- if (isOldProvider(processing.type)) {
- resetOldCtx(processing);
- }
-}
+export function bubbleRender(processing: VNode) {}
// 用于未完成的类组件
export function getIncompleteClassComponent(clazz, processing: VNode, nextProps: object): VNode | null {
diff --git a/libs/horizon/src/renderer/render/FunctionComponent.ts b/libs/horizon/src/renderer/render/FunctionComponent.ts
index 0575257a..af634fe6 100644
--- a/libs/horizon/src/renderer/render/FunctionComponent.ts
+++ b/libs/horizon/src/renderer/render/FunctionComponent.ts
@@ -1,7 +1,6 @@
import type {VNode} from '../Types';
import {mergeDefaultProps} from './LazyComponent';
-import {getOldContext} from '../components/context/CompatibleContext';
import {resetDepContexts} from '../components/context/Context';
import {exeFunctionHook} from '../hooks/HookMain';
import {ForwardRef} from '../vnode/VNodeTags';
@@ -54,11 +53,6 @@ export function captureFunctionComponent(
nextProps: any,
shouldUpdate?: boolean
) {
- let context;
- if (processing.tag !== ForwardRef) {
- context = getOldContext(processing, funcComp, true);
- }
-
resetDepContexts(processing);
const isCanReuse = checkIfCanReuseChildren(processing, shouldUpdate);
@@ -68,7 +62,7 @@ export function captureFunctionComponent(
const newElements = exeFunctionHook(
processing.tag === ForwardRef ? funcComp.render : funcComp,
nextProps,
- processing.tag === ForwardRef ? processing.ref : context,
+ processing.tag === ForwardRef ? processing.ref : undefined,
processing,
);
diff --git a/libs/horizon/src/renderer/render/IncompleteClassComponent.ts b/libs/horizon/src/renderer/render/IncompleteClassComponent.ts
index 2c50ed18..8e02df51 100644
--- a/libs/horizon/src/renderer/render/IncompleteClassComponent.ts
+++ b/libs/horizon/src/renderer/render/IncompleteClassComponent.ts
@@ -4,18 +4,10 @@ import {mergeDefaultProps} from './LazyComponent';
import {ClassComponent} from '../vnode/VNodeTags';
import {resetDepContexts} from '../components/context/Context';
import {getIncompleteClassComponent} from './ClassComponent';
-import {
- isOldProvider,
- resetOldCtx,
- cacheOldCtx,
-} from '../components/context/CompatibleContext';
function captureIncompleteClassComponent(processing, Component, nextProps) {
processing.tag = ClassComponent;
- const hasOldContext = isOldProvider(Component);
- cacheOldCtx(processing, hasOldContext);
-
resetDepContexts(processing);
return getIncompleteClassComponent(Component, processing, nextProps);
@@ -32,10 +24,4 @@ export function captureRender(processing: VNode): VNode | null {
return captureIncompleteClassComponent(processing, Component, resolvedProps);
}
-export function bubbleRender(processing: VNode) {
- // 处理与类组件相同。
- const Component = processing.type;
- if (isOldProvider(Component)) {
- resetOldCtx(processing);
- }
-}
+export function bubbleRender(processing: VNode) {}
diff --git a/libs/horizon/src/renderer/render/SuspenseComponent.ts b/libs/horizon/src/renderer/render/SuspenseComponent.ts
index 3e7bdcb2..28b2c59b 100644
--- a/libs/horizon/src/renderer/render/SuspenseComponent.ts
+++ b/libs/horizon/src/renderer/render/SuspenseComponent.ts
@@ -92,9 +92,11 @@ export function captureSuspenseComponent(processing: VNode) {
if (showFallback) {
processing.suspenseDidCapture = false;
const nextFallbackChildren = nextProps.fallback;
+ debugger
return createFallback(processing, nextFallbackChildren);
} else {
const newChildren = nextProps.children;
+ debugger
return createSuspenseChildren(processing, newChildren);
}
}
diff --git a/libs/horizon/src/renderer/render/TreeRoot.ts b/libs/horizon/src/renderer/render/TreeRoot.ts
index 33a28402..949dc89b 100644
--- a/libs/horizon/src/renderer/render/TreeRoot.ts
+++ b/libs/horizon/src/renderer/render/TreeRoot.ts
@@ -2,13 +2,11 @@ import type {VNode} from '../Types';
import {throwIfTrue} from '../utils/throwIfTrue';
import {processUpdates} from '../UpdateHandler';
import {resetNamespaceCtx, setNamespaceCtx} from '../ContextSaver';
-import {resetOldCtx} from '../components/context/CompatibleContext';
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
import { createChildrenByDiff } from '../diff/nodeDiffComparator';
export function bubbleRender(processing: VNode) {
resetNamespaceCtx(processing);
- resetOldCtx(processing);
}
function updateTreeRoot(processing) {
diff --git a/libs/horizon/src/renderer/vnode/VNodeFlags.ts b/libs/horizon/src/renderer/vnode/VNodeFlags.ts
index 91f59d35..5b72b354 100644
--- a/libs/horizon/src/renderer/vnode/VNodeFlags.ts
+++ b/libs/horizon/src/renderer/vnode/VNodeFlags.ts
@@ -41,6 +41,7 @@ export class FlagUtils {
node.flags |= Addition;
}
static setAddition(node: VNode) {
+ console.log('set addition', node.flags);
node.flags = Addition;
}
From 0b56fb410484204fd1aa4fdc05c363e5ccc6ebaa Mon Sep 17 00:00:00 2001
From: * <8>
Date: Tue, 29 Mar 2022 15:49:54 +0800
Subject: [PATCH 12/13] Match-id-07aa005631c43e03458d2e692810427c7c1cfb59
---
.../src/renderer/render/FunctionComponent.ts | 29 ++++++++++++-------
.../src/renderer/render/SuspenseComponent.ts | 9 +++---
libs/horizon/src/renderer/vnode/VNode.ts | 2 +-
libs/horizon/src/renderer/vnode/VNodeFlags.ts | 3 +-
4 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/libs/horizon/src/renderer/render/FunctionComponent.ts b/libs/horizon/src/renderer/render/FunctionComponent.ts
index af634fe6..a0fba76a 100644
--- a/libs/horizon/src/renderer/render/FunctionComponent.ts
+++ b/libs/horizon/src/renderer/render/FunctionComponent.ts
@@ -1,18 +1,19 @@
-import type {VNode} from '../Types';
+import type { VNode } from '../Types';
-import {mergeDefaultProps} from './LazyComponent';
-import {resetDepContexts} from '../components/context/Context';
-import {exeFunctionHook} from '../hooks/HookMain';
-import {ForwardRef} from '../vnode/VNodeTags';
-import {FlagUtils, Update} from '../vnode/VNodeFlags';
-import {getContextChangeCtx} from '../ContextSaver';
-import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
+import { mergeDefaultProps } from './LazyComponent';
+import { resetDepContexts } from '../components/context/Context';
+import { exeFunctionHook } from '../hooks/HookMain';
+import { ForwardRef } from '../vnode/VNodeTags';
+import { FlagUtils, Update } from '../vnode/VNodeFlags';
+import { getContextChangeCtx } from '../ContextSaver';
+import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator';
import { createChildrenByDiff } from '../diff/nodeDiffComparator';
// 在useState, useReducer的时候,会触发state变化
let stateChange = false;
-export function bubbleRender() {}
+export function bubbleRender() {
+}
// 判断children是否可以复用
function checkIfCanReuseChildren(processing: VNode, shouldUpdate?: boolean) {
@@ -51,8 +52,14 @@ export function captureFunctionComponent(
processing: VNode,
funcComp: any,
nextProps: any,
- shouldUpdate?: boolean
+ shouldUpdate?: boolean,
) {
+ if (processing.isSuspended) {
+ processing.isCreated = true;
+ processing.isSuspended = false;
+
+ FlagUtils.markAddition(processing);
+ }
resetDepContexts(processing);
const isCanReuse = checkIfCanReuseChildren(processing, shouldUpdate);
@@ -89,7 +96,7 @@ export function captureRender(processing: VNode, shouldUpdate?: boolean): VNode
processing,
Component,
resolvedProps,
- shouldUpdate
+ shouldUpdate,
);
}
diff --git a/libs/horizon/src/renderer/render/SuspenseComponent.ts b/libs/horizon/src/renderer/render/SuspenseComponent.ts
index 28b2c59b..0686dc3f 100644
--- a/libs/horizon/src/renderer/render/SuspenseComponent.ts
+++ b/libs/horizon/src/renderer/render/SuspenseComponent.ts
@@ -4,6 +4,7 @@ import {FlagUtils, Interrupted} from '../vnode/VNodeFlags';
import {onlyUpdateChildVNodes, updateVNode, createFragmentVNode} from '../vnode/VNodeCreator';
import {
ClassComponent,
+ FunctionComponent,
IncompleteClassComponent,
SuspenseComponent,
} from '../vnode/VNodeTags';
@@ -21,7 +22,7 @@ export enum SuspenseChildStatus {
// 创建fallback子节点
function createFallback(processing: VNode, fallbackChildren) {
- const childFragment: VNode = processing.child;
+ const childFragment: VNode = processing.child!;
let fallbackFragment;
childFragment.childShouldUpdate = false;
@@ -92,11 +93,9 @@ export function captureSuspenseComponent(processing: VNode) {
if (showFallback) {
processing.suspenseDidCapture = false;
const nextFallbackChildren = nextProps.fallback;
- debugger
return createFallback(processing, nextFallbackChildren);
} else {
const newChildren = nextProps.children;
- debugger
return createSuspenseChildren(processing, newChildren);
}
}
@@ -187,6 +186,9 @@ export function handleSuspenseChildThrowError(parent: VNode, processing: VNode,
}
}
+ if(processing.tag === FunctionComponent) {
+ processing.isSuspended = true;
+ }
// 应该抛出promise未完成更新,标志待更新
processing.shouldUpdate = true;
@@ -225,7 +227,6 @@ export function listenToPromise(suspenseVNode: VNode) {
// 记录已经监听的 promise
let promiseCache = suspenseVNode.realNode;
if (promiseCache === null) {
- // @ts-ignore
promiseCache = new PossiblyWeakSet();
suspenseVNode.realNode = new PossiblyWeakSet();
}
diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts
index 6386fd98..8c98e673 100644
--- a/libs/horizon/src/renderer/vnode/VNode.ts
+++ b/libs/horizon/src/renderer/vnode/VNode.ts
@@ -30,7 +30,7 @@ export class VNode {
updates: any[] | null; // TreeRoot和ClassComponent使用的更新数组
stateCallbacks: any[] | null; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组
isForceUpdate: boolean; // 是否使用强制更新
-
+ isSuspended = false; // 是否被suspense打断更新
state: any; // ClassComponent和TreeRoot的状态
hooks: Array> | null; // 保存hook
suspenseChildStatus = ''; // Suspense的Children是否显示
diff --git a/libs/horizon/src/renderer/vnode/VNodeFlags.ts b/libs/horizon/src/renderer/vnode/VNodeFlags.ts
index 5b72b354..bb811c82 100644
--- a/libs/horizon/src/renderer/vnode/VNodeFlags.ts
+++ b/libs/horizon/src/renderer/vnode/VNodeFlags.ts
@@ -2,7 +2,7 @@
* vNode结构的变化标志
*/
-import type { VNode } from '../Types';
+import type { VNode } from './VNode';
export const InitFlag = /** */ 0;
@@ -41,7 +41,6 @@ export class FlagUtils {
node.flags |= Addition;
}
static setAddition(node: VNode) {
- console.log('set addition', node.flags);
node.flags = Addition;
}
From bc59541e0c692fe037a7b47e0d9c34f8e74b7163 Mon Sep 17 00:00:00 2001
From: * <8>
Date: Tue, 29 Mar 2022 16:07:21 +0800
Subject: [PATCH 13/13] Match-id-6e5a892ace868547d76377206bd2654e93dfc333
---
libs/horizon/src/renderer/render/FunctionComponent.ts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/libs/horizon/src/renderer/render/FunctionComponent.ts b/libs/horizon/src/renderer/render/FunctionComponent.ts
index a0fba76a..8191293b 100644
--- a/libs/horizon/src/renderer/render/FunctionComponent.ts
+++ b/libs/horizon/src/renderer/render/FunctionComponent.ts
@@ -54,11 +54,13 @@ export function captureFunctionComponent(
nextProps: any,
shouldUpdate?: boolean,
) {
+ // 函数组件内已完成异步动作
if (processing.isSuspended) {
+ // 由于首次被打断,应仍为首次渲染
processing.isCreated = true;
- processing.isSuspended = false;
-
FlagUtils.markAddition(processing);
+
+ processing.isSuspended = false;
}
resetDepContexts(processing);