mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
608029aed2
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/42880 Convert `const x = (a: T)` into `const x: T = a`. These are equivalent in Flow, and helps reduce the amount of colon-casts. ``` js1 flow-runner codemod flow/castToAnnotatedVariable --target colon xplat/js ``` Changelog: [Internal] drop-conflicts Reviewed By: SamChou19815 Differential Revision: D53392999 fbshipit-source-id: 3b4602618d6990e8642b423edaeb4e89b01a199a
189 lines
5.3 KiB
JavaScript
189 lines
5.3 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.
|
|
*
|
|
* @flow strict-local
|
|
* @format
|
|
*/
|
|
|
|
import {RNTesterThemeContext} from '../../../components/RNTesterTheme';
|
|
import VCOverlay from './VCOverlayExample';
|
|
import VCTracker from './VCTrackerExample';
|
|
import nullthrows from 'nullthrows';
|
|
import * as React from 'react';
|
|
import {useContext, useEffect} from 'react';
|
|
import {
|
|
ActivityIndicator,
|
|
ScrollView,
|
|
StyleSheet,
|
|
Text,
|
|
View,
|
|
} from 'react-native';
|
|
import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement';
|
|
|
|
export const name = 'Visual Completion Example';
|
|
export const title = name;
|
|
export const description =
|
|
'Example of use of MutationObserver and IntersectionObserver together to track rendering performance.';
|
|
|
|
export function render(): React.Node {
|
|
// We should use the time of the touch up event that lead to this navigation,
|
|
// but we don't have that set up.
|
|
const navigationStartTime = performance.now();
|
|
const vcTracker = new VCTracker(navigationStartTime);
|
|
return <VisualCompletionExample vcTracker={vcTracker} />;
|
|
}
|
|
|
|
/**
|
|
* We are going to track the visual completion of this component, which uses
|
|
* suspense and renders a complex tree in multiple steps.
|
|
*/
|
|
function VisualCompletionExample(props: {vcTracker: VCTracker}): React.Node {
|
|
useEffect(() => {
|
|
return () => props.vcTracker.disconnect();
|
|
}, [props.vcTracker]);
|
|
|
|
return (
|
|
<>
|
|
<VisualCompletionExampleScreen vcTracker={props.vcTracker} />
|
|
<VCOverlay vcTracker={props.vcTracker} />
|
|
</>
|
|
);
|
|
}
|
|
|
|
function VisualCompletionExampleScreen(props: {
|
|
vcTracker: VCTracker,
|
|
}): React.Node {
|
|
const theme = useContext(RNTesterThemeContext);
|
|
|
|
return (
|
|
<View
|
|
id="root-view"
|
|
style={styles.root}
|
|
ref={node => {
|
|
if (node != null) {
|
|
// $FlowExpectedError[incompatible-type]
|
|
const element: ReactNativeElement = node;
|
|
props.vcTracker.addMutationRoot(element);
|
|
}
|
|
}}>
|
|
<View id="header" style={styles.header}>
|
|
<Text style={styles.title} id="header-text">
|
|
Title
|
|
</Text>
|
|
</View>
|
|
<View id="body" style={styles.body}>
|
|
<React.Suspense
|
|
fallback={
|
|
<View id="fallback">
|
|
<ActivityIndicator />
|
|
</View>
|
|
}>
|
|
<ForceSuspense queryID={generateQueryID()} delay={500}>
|
|
<View id="scroll-view-root">
|
|
<ScrollView id="scroll-view">
|
|
<React.Suspense fallback={<ActivityIndicator />}>
|
|
<ForceSuspense queryID={generateQueryID()} delay={2500}>
|
|
<Text
|
|
style={[styles.heading, {color: theme.LabelColor}]}
|
|
id="scroll-view-heading">
|
|
Heading
|
|
</Text>
|
|
</ForceSuspense>
|
|
</React.Suspense>
|
|
<React.Suspense fallback={<ActivityIndicator />}>
|
|
<ForceSuspense queryID={generateQueryID()} delay={4500}>
|
|
<View style={styles.bodyContent} id="scroll-view-content" />
|
|
</ForceSuspense>
|
|
</React.Suspense>
|
|
<Text id="scroll-view-text" style={{color: theme.LabelColor}}>
|
|
{LONG_TEXT}
|
|
</Text>
|
|
</ScrollView>
|
|
</View>
|
|
</ForceSuspense>
|
|
</React.Suspense>
|
|
</View>
|
|
<View id="footer" style={styles.footer}>
|
|
<Text id="footer-text">Example copyright footer</Text>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
function ForceSuspense(props: {
|
|
queryID: string,
|
|
delay: number,
|
|
children: React.Node,
|
|
}): React.Node {
|
|
useForceSuspense(props.queryID, props.delay);
|
|
return props.children;
|
|
}
|
|
|
|
let lastQueryID = 0;
|
|
function generateQueryID() {
|
|
lastQueryID++;
|
|
return 'query-id-' + lastQueryID;
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
root: {
|
|
flex: 1,
|
|
},
|
|
header: {
|
|
padding: 10,
|
|
backgroundColor: 'gray',
|
|
},
|
|
title: {
|
|
textAlign: 'center',
|
|
fontSize: 20,
|
|
},
|
|
body: {
|
|
flex: 1,
|
|
padding: 10,
|
|
},
|
|
heading: {
|
|
fontSize: 16,
|
|
},
|
|
bodyContent: {
|
|
width: 100,
|
|
height: 100,
|
|
backgroundColor: 'blue',
|
|
margin: 50,
|
|
},
|
|
footer: {
|
|
padding: 10,
|
|
backgroundColor: 'gray',
|
|
},
|
|
});
|
|
|
|
const store: Map<string, {promise: Promise<void>, resolved: boolean}> =
|
|
new Map();
|
|
|
|
function useForceSuspense(queryID: string, delay: number): void {
|
|
let entry = store.get(queryID);
|
|
if (!entry) {
|
|
entry = {
|
|
resolved: false,
|
|
promise: new Promise(resolve => {
|
|
setTimeout(() => {
|
|
nullthrows(entry).resolved = true;
|
|
resolve();
|
|
}, delay);
|
|
}),
|
|
};
|
|
store.set(queryID, entry);
|
|
}
|
|
|
|
if (!entry.resolved) {
|
|
throw entry.promise;
|
|
}
|
|
}
|
|
|
|
const LONG_TEXT =
|
|
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas facilisis feugiat ipsum, non placerat nulla. Vestibulum tincidunt eu dui ut bibendum. Cras risus ex, rhoncus auctor velit ut, lobortis convallis turpis. Donec rutrum imperdiet ante, vitae accumsan velit convallis non. Suspendisse feugiat egestas lectus. In eget fringilla ligula, at vehicula orci. Cras laoreet hendrerit urna, sed tincidunt dolor consectetur dapibus.\n'.repeat(
|
|
10,
|
|
);
|