diff --git a/src/Navigation.tsx b/src/Navigation.tsx index 1ade07a357..adfe26ddcd 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -41,7 +41,7 @@ import { type SearchTabNavigatorParams, type State, } from '#/lib/routes/types' -import {logEvent} from '#/lib/statsig/statsig' +import {useRunCallbackOnce} from '#/lib/runCallbackOnce' import {bskyTitle} from '#/lib/strings/headings' import {useUnreadNotifications} from '#/state/queries/notifications/unread' import {useSession} from '#/state/session' @@ -980,15 +980,64 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) { } } - function onReady() { + const onNavigationReady = useRunCallbackOnce(() => { prevLoggedRouteName.current = getCurrentRouteName() + handlePushNotificationEntry() + + ax.metric( + 'router:navigate', + {}, + { + navigation: { + previousScreen: prevLoggedRouteName.current, + currentScreen: getCurrentRouteName(), + }, + }, + ) + if (currentAccount && shouldRequestEmailConfirmation(currentAccount)) { emailDialogControl.open({ id: EmailDialogScreenID.VerificationReminder, }) snoozeEmailConfirmationPrompt() } - } + + ax.metric( + 'init', + { + initMs: Math.round( + // @ts-ignore Emitted by Metro in the bundle prelude + performance.now() - global.__BUNDLE_START_TIME__, + ), + }, + { + navigation: { + previousScreen: prevLoggedRouteName.current, + currentScreen: getCurrentRouteName(), + }, + }, + ) + + if (IS_WEB) { + const referrerInfo = Referrer.getReferrerInfo() + if (referrerInfo && referrerInfo.hostname !== 'bsky.app') { + ax.metric( + 'deepLink:referrerReceived', + { + to: window.location.href, + referrer: referrerInfo?.referrer, + hostname: referrerInfo?.hostname, + }, + { + navigation: { + previousScreen: prevLoggedRouteName.current, + currentScreen: getCurrentRouteName(), + }, + }, + ) + } + } + }) return ( ) { ) prevLoggedRouteName.current = getCurrentRouteName() }} - onReady={() => { - logModuleInitTime() - onReady() - ax.metric( - 'router:navigate', - {}, - { - navigation: { - previousScreen: prevLoggedRouteName.current, - currentScreen: getCurrentRouteName(), - }, - }, - ) - handlePushNotificationEntry() - }} + onReady={onNavigationReady} // WARNING: Implicit navigation to nested navigators is depreciated in React Navigation 7.x // However, there's a fair amount of places we do that, especially in when popping to the top of stacks. // See BottomBar.tsx for an example of how to handle nested navigators in the tabs correctly. @@ -1113,44 +1148,6 @@ function reset(): Promise { } } -let didInit = false -function logModuleInitTime() { - if (didInit) { - return - } - didInit = true - - const initMs = Math.round( - // @ts-ignore Emitted by Metro in the bundle prelude - performance.now() - global.__BUNDLE_START_TIME__, - ) - console.log(`Time to first paint: ${initMs} ms`) - logEvent('init', { - initMs, - }) - - if (IS_WEB) { - const referrerInfo = Referrer.getReferrerInfo() - if (referrerInfo && referrerInfo.hostname !== 'bsky.app') { - logEvent('deepLink:referrerReceived', { - to: window.location.href, - referrer: referrerInfo?.referrer, - hostname: referrerInfo?.hostname, - }) - } - } - - if (__DEV__) { - // This log is noisy, so keep false committed - const shouldLog = false - // Relies on our patch to polyfill.js in metro-runtime - const initLogs = (global as any).__INIT_LOGS__ - if (shouldLog && Array.isArray(initLogs)) { - console.log(initLogs.join('\n')) - } - } -} - export { FlatNavigator, navigate, diff --git a/src/lib/runCallbackOnce.ts b/src/lib/runCallbackOnce.ts new file mode 100644 index 0000000000..4be1afb4da --- /dev/null +++ b/src/lib/runCallbackOnce.ts @@ -0,0 +1,21 @@ +import {useCallback, useRef} from 'react' + +export function createRunCallbackOnce() { + let hasRun = false + return function runCallbackOnce(callback: () => void) { + if (!hasRun) { + hasRun = true + callback() + } + } +} + +export function useRunCallbackOnce(callback: () => void) { + const hasRunRef = useRef(false) + return useCallback(() => { + if (!hasRunRef.current) { + hasRunRef.current = true + callback() + } + }, [callback]) +}