This repository was archived by the owner on Nov 26, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy pathReactNavigationPerformanceView.tsx
More file actions
84 lines (72 loc) · 3.52 KB
/
ReactNavigationPerformanceView.tsx
File metadata and controls
84 lines (72 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import React, {useEffect, useState, useRef, useCallback} from 'react';
import type {ComponentProps} from 'react';
import {PerformanceMeasureView, inMemoryCounter, useStateController} from '@shopify/react-native-performance';
import {useNavigation} from '@react-navigation/native';
import {useFocusEffect} from '@react-navigation/core';
import type {ParamListBase} from '@react-navigation/native';
import type {StackNavigationProp} from '@react-navigation/stack';
const TRANSITION_END = 'transition-end';
export type Props = ComponentProps<typeof PerformanceMeasureView>;
/**
* Performance view similar to `PerformanceMeasureView` but meant to be used with `react-navigation`.
* If the screen is not mounted in a react-navigation context, it might misbehave and is therefore not recommended.
*/
export const ReactNavigationPerformanceView = (props: Props) => {
const {addListener, getState} = useNavigation<StackNavigationProp<ParamListBase>>();
// Stack is the only navigation type that has a `transitionEnd` event.
const isStack = getState().type === 'stack';
const [transitionEnded, setTransitionEnded] = useState(!isStack);
// We only want to report `TRANSITION_END` render pass once.
const transitionEndReported = useRef(false);
const componentInstanceId = useRef(props.componentInstanceId ?? inMemoryCounter()).current;
const stateController = useStateController();
useFocusEffect(
useCallback(() => {
stateController.stopFlowIfNeeded(componentInstanceId);
}, [stateController, componentInstanceId]),
);
useEffect(() => {
if (!isStack || !stateController.isEnabled) {
return;
}
return addListener('transitionEnd', () => {
setTransitionEnded(true);
});
}, [addListener, isStack, stateController.isEnabled]);
let shouldReportTransitionEnd = false;
if (isStack && transitionEnded && transitionEndReported.current === false) {
shouldReportTransitionEnd = true;
transitionEndReported.current = true;
}
// View can be interactive only when the present animation has completed (marked by `transitionEnd` event).
// However, we wait for `transitionEnd` event only in case when we are in a context of a stack navigator as otherwise `transitionEnd` never occurs.
const interactive = props.interactive === true && transitionEnded;
/**
* Represents previous renderPassName passed via `props`.
* Does not include `TRANSITION_END` event.
*/
const lastRenderPassName = useRef<string | undefined>(undefined);
const renderProps = useRef({
renderPassName: props.renderPassName,
interactive,
});
// If a user has not changed the `renderPassName`, we keep `TRANSITION_END` as the current one.
// This is to avoid emitting reports of render passes where user has not explicitly changed it.
// `PerformanceMeasureView` will log a reused `renderPassName`
// and subsequent render passes with a different `renderPassName` will still be reported.
// Check out this link for more details: https://github.com/Shopify/react-native-performance/pull/363
if (shouldReportTransitionEnd) {
renderProps.current = {renderPassName: TRANSITION_END, interactive};
} else if (lastRenderPassName.current !== props.renderPassName) {
renderProps.current = {renderPassName: props.renderPassName, interactive};
}
lastRenderPassName.current = props.renderPassName;
return (
<PerformanceMeasureView
{...props}
componentInstanceId={componentInstanceId}
renderPassName={renderProps.current.renderPassName}
interactive={renderProps.current.interactive}
/>
);
};