mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
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
128 lines
2.8 KiB
JavaScript
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',
|
|
},
|
|
});
|