UNPKG

@datadog/mobile-react-native

Version:

A client-side React Native module to interact with Datadog

126 lines (122 loc) 5.19 kB
/* * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. * This product includes software developed at Datadog (https://www.datadoghq.com/). * Copyright 2016-Present Datadog, Inc. */ import React from 'react'; import { InternalLog } from '../../../InternalLog'; import { SdkVerbosity } from '../../../SdkVerbosity'; import { DdSdk } from '../../../sdk/DdSdk'; import { getErrorMessage } from '../../../utils/errorUtils'; import { BABEL_PLUGIN_TELEMETRY } from '../../constants'; import { DdBabelInteractionTracking } from './DdBabelInteractionTracking'; import { DdEventsInterceptor } from './DdEventsInterceptor'; import { NoOpEventsInterceptor } from './NoOpEventsInterceptor'; import { areObjectShallowEqual } from './ShallowObjectEqualityChecker'; import { getJsxRuntimes } from './getJsxRuntime'; /** * Provides RUM auto-instrumentation feature to track user interaction as RUM events. * For now we are only covering the "onPress" events. */ export class DdRumUserInteractionTracking { static isTracking = false; static eventsInterceptor = new NoOpEventsInterceptor(); static originalCreateElement = React.createElement; static originalMemo = React.memo; static originalJsx = null; static originalDevJsx = null; static patchCreateElementFunction = (originalFunction, [element, props, ...rest]) => { if (props && typeof props.onPress === 'function') { const originalOnPress = props // eslint-disable-next-line @typescript-eslint/ban-types .onPress; props.onPress = (...args) => { DdRumUserInteractionTracking.eventsInterceptor.interceptOnPress(...args); return originalOnPress(...args); }; // we store the original onPress prop so we can keep memoization working props.__DATADOG_INTERNAL_ORIGINAL_ON_PRESS__ = originalOnPress; } return originalFunction(element, props, ...rest); }; /** * Starts tracking user interactions and sends a RUM Action event every time a new interaction was detected. * Please note that we are only considering as valid - for - tracking only the user interactions that have * a visible output (either an UI state change or a Resource request) */ static startTracking(options) { // extra safety to avoid wrapping more than 1 time this function if (DdRumUserInteractionTracking.isTracking) { InternalLog.log('Datadog SDK is already tracking interactions', SdkVerbosity.WARN); return; } DdSdk?.sendTelemetryLog(BABEL_PLUGIN_TELEMETRY, DdBabelInteractionTracking.getTelemetryConfig(), { onlyOnce: true }); DdRumUserInteractionTracking.eventsInterceptor = new DdEventsInterceptor(options); const original = React.createElement; React.createElement = (...args) => { return this.patchCreateElementFunction(original, args); }; try { const [jsxRuntime, jsxDevRuntime] = getJsxRuntimes(); const originalJsx = jsxRuntime?.jsx; const originalDevJsx = jsxDevRuntime?.jsxDEV; this.originalJsx = originalJsx; this.originalDevJsx = originalDevJsx; if (originalJsx) { jsxRuntime.jsx = (...args) => { return this.patchCreateElementFunction(originalJsx, args); }; } if (originalDevJsx) { jsxRuntime.jsxDEV = (...args) => { return this.patchCreateElementFunction(originalDevJsx, args); }; } } catch (e) { DdSdk.telemetryDebug(getErrorMessage(e)); } const originalMemo = React.memo; React.memo = (component, propsAreEqual) => { return originalMemo(component, (prev, next) => { if (!next.onPress || !prev.onPress) { return propsAreEqual ? propsAreEqual(prev, next) : areObjectShallowEqual(prev, next); } // we replace "our" onPress from the props by the original for comparison const { onPress: _prevOnPress, ...partialPrevProps } = prev; const prevProps = { ...partialPrevProps, onPress: prev.__DATADOG_INTERNAL_ORIGINAL_ON_PRESS__ }; const { onPress: _nextOnPress, ...partialNextProps } = next; const nextProps = { ...partialNextProps, onPress: next.__DATADOG_INTERNAL_ORIGINAL_ON_PRESS__ }; // if no comparison function is provided we do shallow comparison return propsAreEqual ? propsAreEqual(prevProps, nextProps) : areObjectShallowEqual(nextProps, prevProps); }); }; DdRumUserInteractionTracking.isTracking = true; InternalLog.log('Datadog SDK is tracking interactions', SdkVerbosity.INFO); } static stopTracking() { React.createElement = this.originalCreateElement; React.memo = this.originalMemo; DdRumUserInteractionTracking.isTracking = false; if (this.originalJsx || this.originalDevJsx) { const [jsxRuntime, jsxDevRuntime] = getJsxRuntimes(); jsxRuntime.jsx = this.originalJsx; jsxDevRuntime.jsxDEV = this.originalDevJsx; this.originalJsx = null; this.originalDevJsx = null; } } } //# sourceMappingURL=DdRumUserInteractionTracking.js.map