mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
introduce a way to inspect shadow node revision in Fantom (#51566)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/51566 changelog: [internal] Expose [revision](https://github.com/facebook/react-native/blob/main/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h#L229) of shadow node in Fantom tests. This makes it possible to write tests verifying that shadow nodes are only cloned when they should. Even though excessive cloning does not usually lead to bugs, it may lead to performance problems. Also introduce a test showing a performance problem where changing height of "Sibling" view from 1 to 2 will lead to component `D` being cloned by Yoga. Component D is not affected by the size change of Sibling and the clone is unnecessary. ```jsx <ScrollView> <View id="Sibling" style={{ height: 1 }} /> <View id="A"> <View id="B"> <View id="C"> <View id="D" ref={ref} /> </View> </View> </View> </ScrollView> ``` Reviewed By: rshest Differential Revision: D75287261 fbshipit-source-id: ea5acb2f5d7ba6e1e5bf895d8f82a16471122ec5
This commit is contained in:
committed by
Facebook GitHub Bot
parent
ca5f4d1721
commit
afb543683c
+13
@@ -616,6 +616,19 @@ export function createShadowNodeReferenceCounter(
|
||||
return NativeFantom.createShadowNodeReferenceCounter(shadowNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function that returns the current revision number for the supplied
|
||||
* element's shadow node.
|
||||
*
|
||||
* @param node The node for which to create a revision getter.
|
||||
*/
|
||||
export function createShadowNodeRevisionGetter(
|
||||
node: ReactNativeElement,
|
||||
): () => ?number {
|
||||
let shadowNode = getNativeNodeReference(node);
|
||||
return NativeFantom.createShadowNodeRevisionGetter(shadowNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a heap snapshot after forcing garbage collection.
|
||||
*
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import ReactNativeElement from '../../webapis/dom/nodes/ReadOnlyNode';
|
||||
import ensureInstance from './ensureInstance';
|
||||
import * as Fantom from '@react-native/fantom';
|
||||
|
||||
function createShadowNodeRevisionGetter(
|
||||
element: ReactNativeElement,
|
||||
): () => ?number {
|
||||
const getRevision = Fantom.createShadowNodeRevisionGetter(element);
|
||||
return () => {
|
||||
return getRevision();
|
||||
};
|
||||
}
|
||||
|
||||
export function createShadowNodeReferenceGetterRef(): [
|
||||
() => ?number,
|
||||
React.RefSetter<mixed>,
|
||||
] {
|
||||
let getRevision: ?() => ?number;
|
||||
|
||||
function getShadowNodeReferenceCount() {
|
||||
if (getRevision == null) {
|
||||
throw new Error('ShadowNode revision getter was not initialized.');
|
||||
}
|
||||
return getRevision();
|
||||
}
|
||||
|
||||
function ref(instance: mixed | null) {
|
||||
if (instance == null) {
|
||||
return;
|
||||
}
|
||||
const element = ensureInstance(instance, ReactNativeElement);
|
||||
if (getRevision != null) {
|
||||
throw new Error('ShadowNode revision getter was already initialized.');
|
||||
}
|
||||
getRevision = createShadowNodeRevisionGetter(element);
|
||||
}
|
||||
|
||||
return [getShadowNodeReferenceCount, ref];
|
||||
}
|
||||
Vendored
+74
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
|
||||
|
||||
import {createShadowNodeReferenceGetterRef} from '../ShadowNodeRevisionGetter';
|
||||
import * as Fantom from '@react-native/fantom';
|
||||
import * as React from 'react';
|
||||
import {ScrollView, View} from 'react-native';
|
||||
|
||||
test('base case when cloning results in revision +1', () => {
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
const [getRevision, ref] = createShadowNodeReferenceGetterRef();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<View ref={ref} />);
|
||||
});
|
||||
|
||||
expect(getRevision()).toBe(1);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<View nativeID="updated" ref={ref} />);
|
||||
});
|
||||
|
||||
expect(getRevision()).toBe(2);
|
||||
});
|
||||
|
||||
test('changing height of the top item in ScrollView results in excessive cloning', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const [getRevision, ref] = createShadowNodeReferenceGetterRef();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<ScrollView>
|
||||
<View id="Sibling" style={{height: 1}} />
|
||||
<View id="A">
|
||||
<View id="B">
|
||||
<View id="C">
|
||||
<View id="D" ref={ref} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>,
|
||||
);
|
||||
});
|
||||
|
||||
expect(getRevision()).toBe(1);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<ScrollView>
|
||||
<View id="Sibling" style={{height: 2}} />
|
||||
<View id="A">
|
||||
<View id="B">
|
||||
<View id="C">
|
||||
<View id="D" ref={ref} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>,
|
||||
);
|
||||
});
|
||||
|
||||
// TODO(T225268793): the below assertion should be: `expect(getRevision()).toBe(1);`
|
||||
expect(getRevision()).toBe(2);
|
||||
});
|
||||
@@ -96,6 +96,9 @@ interface Spec extends TurboModule {
|
||||
createShadowNodeReferenceCounter(
|
||||
shadowNode: mixed /* ShadowNode */,
|
||||
): () => number;
|
||||
createShadowNodeRevisionGetter(
|
||||
shadowNode: mixed /* ShadowNode */,
|
||||
): () => ?number;
|
||||
saveJSMemoryHeapSnapshot: (filePath: string) => void;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user