修复StrictMode组件导致子组件状态丢失的问题
This commit is contained in:
parent
5b0ed0a5aa
commit
0022a6b55a
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
|
||||||
|
*
|
||||||
|
* openInula is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
*
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Inula from '../../../src/index';
|
||||||
|
import { getLogUtils } from '../jest/testUtils';
|
||||||
|
|
||||||
|
describe('StrictMode Component test', () => {
|
||||||
|
const LogUtils = getLogUtils();
|
||||||
|
const { useState, useEffect, useRef, render, act } = Inula;
|
||||||
|
it('StrictMode is same to Fragment', () => {
|
||||||
|
const Parent = () => {
|
||||||
|
const [, setS] = useState('1');
|
||||||
|
return (
|
||||||
|
<Inula.StrictMode>
|
||||||
|
<button id="btn" onClick={() => setS(prevState => prevState + '!')}>
|
||||||
|
Click
|
||||||
|
</button>
|
||||||
|
<Child />
|
||||||
|
</Inula.StrictMode>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Child = () => {
|
||||||
|
const isMount = useRef(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isMount.current) {
|
||||||
|
LogUtils.log('didMount');
|
||||||
|
isMount.current = true;
|
||||||
|
} else {
|
||||||
|
LogUtils.log('didUpdate');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
act(() => render(<Parent />, container));
|
||||||
|
// 子组件初始化,会挂载一次
|
||||||
|
expect(LogUtils.getAndClear()).toStrictEqual(['didMount']);
|
||||||
|
const button = container.querySelector('#btn');
|
||||||
|
// 父组件State更新,子组件也会更新一次
|
||||||
|
act(() => button.click());
|
||||||
|
expect(LogUtils.getAndClear()).toStrictEqual(['didUpdate']);
|
||||||
|
});
|
||||||
|
});
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
import type { VNode } from '../Types';
|
import type { VNode } from '../Types';
|
||||||
import { FlagUtils } from '../vnode/VNodeFlags';
|
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||||
import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL } from '../../external/JSXElementType';
|
import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL, TYPE_STRICT_MODE } from '../../external/JSXElementType';
|
||||||
import { DomText, DomPortal, Fragment, DomComponent } from '../vnode/VNodeTags';
|
import { DomText, DomPortal, Fragment, DomComponent } from '../vnode/VNodeTags';
|
||||||
import {
|
import {
|
||||||
updateVNode,
|
updateVNode,
|
||||||
|
@ -35,9 +35,9 @@ enum DiffCategory {
|
||||||
ARR_NODE = 'ARR_NODE',
|
ARR_NODE = 'ARR_NODE',
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是不是被 FRAGMENT 包裹
|
// 检查是不是被 FRAGMENT 或 StrictMode 包裹
|
||||||
function isNoKeyFragment(child: any) {
|
function isNoKeyFragmentOrStrictMode(child: any) {
|
||||||
return child != null && child.type === TYPE_FRAGMENT && child.key === null;
|
return child != null && (child.type === TYPE_FRAGMENT || child.type === TYPE_STRICT_MODE) && child.key === null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清除单个节点
|
// 清除单个节点
|
||||||
|
@ -631,7 +631,7 @@ export function createChildrenByDiff(
|
||||||
newChild: any,
|
newChild: any,
|
||||||
isComparing: boolean
|
isComparing: boolean
|
||||||
): VNode | null {
|
): VNode | null {
|
||||||
const isFragment = isNoKeyFragment(newChild);
|
const isFragment = isNoKeyFragmentOrStrictMode(newChild);
|
||||||
newChild = isFragment ? newChild.props.children : newChild;
|
newChild = isFragment ? newChild.props.children : newChild;
|
||||||
|
|
||||||
// 1. 没有新节点,直接把vNode标记为删除
|
// 1. 没有新节点,直接把vNode标记为删除
|
||||||
|
|
Loading…
Reference in New Issue