Skip to content

Commit 643c544

Browse files
ref: Navigation Integrations with new function style (#4003)
1 parent eeb83da commit 643c544

25 files changed

+681
-873
lines changed

CHANGELOG.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,44 @@
3939
});
4040
```
4141

42+
- New React Navigation Integration interface ([#4003](https://github.com/getsentry/sentry-react-native/pull/4003))
43+
44+
```js
45+
import Sentry from '@sentry/react-native';
46+
import { NavigationContainer } from '@react-navigation/native';
47+
48+
const reactNavigationIntegration = Sentry.reactNavigationIntegration();
49+
50+
Sentry.init({
51+
tracesSampleRate: 1.0,
52+
integrations: [reactNavigationIntegration],
53+
});
54+
55+
function RootComponent() {
56+
const navigation = React.useRef(null);
57+
58+
return <NavigationContainer ref={navigation}
59+
onReady={() => {
60+
reactNavigationIntegration.registerNavigationContainer(navigation);
61+
}}>
62+
</NavigationContainer>;
63+
}
64+
```
65+
66+
- New React Native Navigation Integration interface ([#4003](https://github.com/getsentry/sentry-react-native/pull/4003))
67+
68+
```js
69+
import Sentry from '@sentry/react-native';
70+
import { Navigation } from 'react-native-navigation';
71+
72+
Sentry.init({
73+
tracesSampleRate: 1.0,
74+
integrations: [
75+
Sentry.reactNativeNavigationIntegration({ navigation: Navigation })
76+
],
77+
});
78+
```
79+
4280
### Features
4381

4482
- `TimeToInitialDisplay` and `TimeToFullDisplay` start the time to display spans on mount ([#4020](https://github.com/getsentry/sentry-react-native/pull/4020))

samples/expo/app/_layout.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ LogBox.ignoreAllLogs();
2121
// Prevent the splash screen from auto-hiding before asset loading is complete.
2222
SplashScreen.preventAutoHideAsync();
2323

24-
const routingInstrumentation = new Sentry.ReactNavigationInstrumentation({
24+
const navigationIntegration = Sentry.reactNavigationIntegration({
2525
enableTimeToInitialDisplay: !isExpoGo(), // This is not supported in Expo Go.
2626
});
2727

@@ -54,9 +54,8 @@ process.env.EXPO_SKIP_DURING_EXPORT !== 'true' && Sentry.init({
5454
// default: [/.*/]
5555
failedRequestTargets: [/.*/],
5656
}),
57-
Sentry.reactNativeTracingIntegration({
58-
routingInstrumentation,
59-
}),
57+
navigationIntegration,
58+
Sentry.reactNativeTracingIntegration(),
6059
);
6160
return integrations.filter(i => i.name !== 'Dedupe');
6261
},
@@ -91,7 +90,7 @@ function RootLayout() {
9190

9291
useEffect(() => {
9392
if (ref) {
94-
routingInstrumentation.registerNavigationContainer(ref);
93+
navigationIntegration.registerNavigationContainer(ref);
9594
}
9695
}, [ref]);
9796

samples/react-native/src/App.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ LogBox.ignoreAllLogs();
3838

3939
const isMobileOs = Platform.OS === 'android' || Platform.OS === 'ios';
4040

41-
const reactNavigationInstrumentation =
42-
new Sentry.ReactNavigationInstrumentation({
43-
routeChangeTimeoutMs: 500, // How long it will wait for the route change to complete. Default is 1000ms
44-
enableTimeToInitialDisplay: isMobileOs,
45-
});
41+
const reactNavigationIntegration = Sentry.reactNavigationIntegration({
42+
routeChangeTimeoutMs: 500, // How long it will wait for the route change to complete. Default is 1000ms
43+
enableTimeToInitialDisplay: isMobileOs,
44+
ignoreEmptyBackNavigationTransactions: true,
45+
});
4646

4747
Sentry.init({
4848
// Replace the example DSN below with your own DSN:
@@ -66,11 +66,10 @@ Sentry.init({
6666
},
6767
integrations(integrations) {
6868
integrations.push(
69+
reactNavigationIntegration,
6970
Sentry.reactNativeTracingIntegration({
7071
// The time to wait in ms until the transaction will be finished, For testing, default is 1000 ms
7172
idleTimeoutMs: 5_000,
72-
routingInstrumentation: reactNavigationInstrumentation,
73-
ignoreEmptyBackNavigationTransactions: true,
7473
}),
7574
Sentry.httpClientIntegration({
7675
// These options are effective only in JS.
@@ -183,7 +182,7 @@ function BottomTabs() {
183182
<NavigationContainer
184183
ref={navigation}
185184
onReady={() => {
186-
reactNavigationInstrumentation.registerNavigationContainer(navigation);
185+
reactNavigationIntegration.registerNavigationContainer(navigation);
187186
}}>
188187
<Tab.Navigator
189188
screenOptions={{

src/js/client.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@ import type {
1414
import { dateTimestampInSeconds, logger, SentryError } from '@sentry/utils';
1515
import { Alert } from 'react-native';
1616

17-
import { createIntegration } from './integrations/factory';
1817
import { defaultSdkInfo } from './integrations/sdkinfo';
1918
import type { ReactNativeClientOptions } from './options';
2019
import type { mobileReplayIntegration } from './replay/mobilereplay';
2120
import { MOBILE_REPLAY_INTEGRATION_NAME } from './replay/mobilereplay';
22-
import { getReactNativeTracingIntegration } from './tracing/reactnativetracing';
2321
import { createUserFeedbackEnvelope, items } from './utils/envelope';
2422
import { ignoreRequireCycleLogs } from './utils/ignorerequirecyclelogs';
2523
import { mergeOutcomes } from './utils/outcome';
@@ -136,18 +134,6 @@ export class ReactNativeClient extends BaseClient<ReactNativeClientOptions> {
136134
this._initNativeSdk();
137135
}
138136

139-
/**
140-
* @inheritdoc
141-
*/
142-
protected _setupIntegrations(): void {
143-
super._setupIntegrations();
144-
const tracing = getReactNativeTracingIntegration(this);
145-
const routingName = tracing?.options?.routingInstrumentation?.name;
146-
if (routingName) {
147-
this.addIntegration(createIntegration(routingName));
148-
}
149-
}
150-
151137
/**
152138
* Starts native client with dsn and options
153139
*/

src/js/index.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,18 @@ export { TouchEventBoundary, withTouchEventBoundary } from './touchevents';
5959

6060
export {
6161
reactNativeTracingIntegration,
62-
ReactNavigationV5Instrumentation,
63-
ReactNavigationInstrumentation,
64-
ReactNativeNavigationInstrumentation,
65-
RoutingInstrumentation,
62+
getCurrentReactNativeTracingIntegration,
63+
getReactNativeTracingIntegration,
64+
reactNavigationIntegration,
65+
reactNativeNavigationIntegration,
6666
sentryTraceGesture,
6767
TimeToInitialDisplay,
6868
TimeToFullDisplay,
6969
startTimeToInitialDisplaySpan,
7070
startTimeToFullDisplaySpan,
71+
startIdleNavigationSpan,
72+
startIdleSpan,
73+
getDefaultIdleNavigationSpanOptions,
7174
} from './tracing';
7275

7376
export type { TimeToDisplayProps } from './tracing';

src/js/tracing/index.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
export {
22
reactNativeTracingIntegration,
33
INTEGRATION_NAME as REACT_NATIVE_TRACING_INTEGRATION_NAME,
4+
getCurrentReactNativeTracingIntegration,
5+
getReactNativeTracingIntegration,
46
} from './reactnativetracing';
57
export type { ReactNativeTracingIntegration } from './reactnativetracing';
68

7-
export type { RoutingInstrumentationInstance } from './routingInstrumentation';
8-
export { RoutingInstrumentation } from './routingInstrumentation';
9+
export { reactNavigationIntegration } from './reactnavigation';
10+
export { reactNativeNavigationIntegration } from './reactnativenavigation';
911

10-
export {
11-
ReactNavigationInstrumentation,
12-
// eslint-disable-next-line deprecation/deprecation
13-
ReactNavigationV5Instrumentation,
14-
} from './reactnavigation';
15-
export { ReactNativeNavigationInstrumentation } from './reactnativenavigation';
12+
export { startIdleNavigationSpan, startIdleSpan, getDefaultIdleNavigationSpanOptions } from './span';
1613

1714
export type { ReactNavigationCurrentRoute, ReactNavigationRoute } from './types';
1815

src/js/tracing/integrations/appStart.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import {
2222
APP_START_WARM as APP_START_WARM_OP,
2323
UI_LOAD as UI_LOAD_OP,
2424
} from '../ops';
25-
import { getReactNativeTracingIntegration } from '../reactnativetracing';
2625
import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '../semanticAttributes';
2726
import { createChildSpanJSON, createSpanJSON, getBundleStartTimestampMs } from '../utils';
2827

@@ -97,7 +96,7 @@ export function _clearRootComponentCreationTimestampMs(): void {
9796
* Adds AppStart spans from the native layer to the transaction event.
9897
*/
9998
export const appStartIntegration = ({
100-
standalone: standaloneUserOption,
99+
standalone = false,
101100
}: {
102101
/**
103102
* Should the integration send App Start as a standalone root span (transaction)?
@@ -108,7 +107,6 @@ export const appStartIntegration = ({
108107
standalone?: boolean;
109108
} = {}): AppStartIntegration => {
110109
let _client: Client | undefined = undefined;
111-
let standalone = standaloneUserOption;
112110
let isEnabled = true;
113111
let appStartDataFlushed = false;
114112

@@ -123,11 +121,8 @@ export const appStartIntegration = ({
123121
}
124122
};
125123

126-
const afterAllSetup = (client: Client): void => {
127-
if (standaloneUserOption === undefined) {
128-
// If not user defined, set based on the routing instrumentation presence
129-
standalone = !getReactNativeTracingIntegration(client)?.options.routingInstrumentation;
130-
}
124+
const afterAllSetup = (_client: Client): void => {
125+
// TODO: automatically set standalone based on the presence of the native layer navigation integration
131126
};
132127

133128
const processEvent = async (event: Event): Promise<Event> => {

src/js/tracing/onSpanEndUtils.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { AppState } from 'react-native';
77
import { isRootSpan, isSentrySpan } from '../utils/span';
88

99
/**
10-
*
10+
* Hooks on span end event to execute a callback when the span ends.
1111
*/
1212
export function onThisSpanEnd(client: Client, span: Span, callback: (span: Span) => void): void {
1313
client.on('spanEnd', (endedSpan: Span) => {
@@ -44,7 +44,18 @@ export const adjustTransactionDuration = (client: Client, span: Span, maxDuratio
4444
}
4545
});
4646
};
47-
export const ignoreEmptyBackNavigation = (client: Client, span: Span): void => {
47+
48+
export const ignoreEmptyBackNavigation = (client: Client | undefined, span: Span): void => {
49+
if (!client) {
50+
logger.warn('Could not hook on spanEnd event because client is not defined.');
51+
return;
52+
}
53+
54+
if (!span) {
55+
logger.warn('Could not hook on spanEnd event because span is not defined.');
56+
return;
57+
}
58+
4859
if (!isRootSpan(span) || !isSentrySpan(span)) {
4960
logger.warn('Not sampling empty back spans only works for Sentry Transactions (Root Spans).');
5061
return;
@@ -70,7 +81,7 @@ export const ignoreEmptyBackNavigation = (client: Client, span: Span): void => {
7081
if (filtered.length <= 0) {
7182
// filter children must include at least one span not created by the navigation automatic instrumentation
7283
logger.log(
73-
'[ReactNativeTracing] Not sampling transaction as route has been seen before. Pass ignoreEmptyBackNavigationTransactions = false to disable this feature.',
84+
'Not sampling transaction as route has been seen before. Pass ignoreEmptyBackNavigationTransactions = false to disable this feature.',
7485
);
7586
// Route has been seen before and has no child spans.
7687
span['_sampled'] = false;

0 commit comments

Comments
 (0)