Files
react-native/packages/rn-tester/js/examples/IntersectionObserver/IntersectionObserverBenchmark.js
T
Rubén Norte a94bbfbe0e Enable IntersectionObserver in Catalyst and RNTester (#37863)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37863

This creates 2 examples for IntersectionObserver in RNTester:
* The first example is just a copy of the example provided by MDN in the documentation page for `IntersectionObserver` (https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). This example is useful to show how React Native behaves the same way with the same code.
* The second example is a "stress test" for the API: a screen with 500 simultaneous node being observed at the same time with different observers. As we compute the intersections after scroll (after "mounting" the state update with the updated scroll position) in the main thread, this highlights a possible impact on scroll performance.

IntersectionObserver isn't yet enabled by default, so no need to add a changelog entry about this. We'll add one when the API becomes generally available.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D45736845

fbshipit-source-id: 40b6bce39f90e04653504b1033a4edfaa65e93ca
2023-06-23 02:56:04 -07:00

128 lines
2.8 KiB
JavaScript

/**
* 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.
*
* @format
* @flow strict-local
*/
import {RNTesterThemeContext} from '../../components/RNTesterTheme';
import * as React from 'react';
import {
useLayoutEffect,
useState,
useRef,
type ElementRef,
useContext,
} from 'react';
import {Button, ScrollView, StyleSheet, Text, View} from 'react-native';
export const name = 'IntersectionObserver Benchmark';
export const title = name;
export const description =
'Example of using IntersectionObserver to observe a large amount of UI elements';
export function render(): React.Node {
return <IntersectionObserverBenchark />;
}
const ROWS = 100;
const COLUMNS = 5;
function IntersectionObserverBenchark(): React.Node {
const [isObserving, setObserving] = useState(false);
return (
<>
<View style={styles.buttonContainer}>
<Button
title={isObserving ? 'Stop observing' : 'Start observing'}
onPress={() => setObserving(observing => !observing)}
/>
</View>
<ScrollView>
{Array(ROWS)
.fill(null)
.map((_, row) => (
<View style={styles.row} key={row}>
{Array(COLUMNS)
.fill(null)
.map((_2, column) => (
<Item
index={COLUMNS * row + column}
observe={isObserving}
key={column}
/>
))}
</View>
))}
</ScrollView>
</>
);
}
function Item({index, observe}: {index: number, observe: boolean}): React.Node {
const theme = useContext(RNTesterThemeContext);
const ref = useRef<?ElementRef<typeof View>>();
useLayoutEffect(() => {
const element = ref.current;
if (!observe || !element) {
return;
}
const observer = new IntersectionObserver(
entries => {
// You can inspect the actual entries here.
// We don't log them by default to avoid the logs themselves to degrade
// performance.
},
{
threshold: [0, 1],
},
);
// $FlowExpectedError
observer.observe(element);
return () => {
observer.disconnect();
};
}, [observe]);
return (
<View
ref={ref}
style={[
styles.item,
{backgroundColor: theme.SecondarySystemBackgroundColor},
]}>
<Text style={[styles.itemText, {color: theme.LabelColor}]}>
{index + 1}
</Text>
</View>
);
}
const styles = StyleSheet.create({
buttonContainer: {
padding: 10,
},
row: {
flexDirection: 'row',
},
item: {
flex: 1,
padding: 12,
margin: 5,
},
itemText: {
fontSize: 22,
textAlign: 'center',
},
});