diff --git a/src/hooks/useSidebarOrderedReports.tsx b/src/hooks/useSidebarOrderedReports.tsx
index e6951ca4f5fd..ed55aacb5918 100644
--- a/src/hooks/useSidebarOrderedReports.tsx
+++ b/src/hooks/useSidebarOrderedReports.tsx
@@ -1,5 +1,7 @@
-import React, {createContext, useCallback, useContext, useEffect, useMemo, useState} from 'react';
+import {deepEqual} from 'fast-equals';
+import React, {createContext, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
+import Log from '@libs/Log';
import {getPolicyEmployeeListByIdWithoutCurrentUser} from '@libs/PolicyUtils';
import SidebarUtils from '@libs/SidebarUtils';
import CONST from '@src/CONST';
@@ -224,6 +226,53 @@ function SidebarOrderedReportsContextProvider({
};
}, [getOrderedReportIDs, orderedReportIDs, derivedCurrentReportID, policyMemberAccountIDs, shouldUseNarrowLayout, getOrderedReports, orderedReports]);
+ const currentDeps = {
+ priorityMode,
+ chatReports,
+ policies,
+ transactions,
+ transactionViolations,
+ reportNameValuePairs,
+ betas,
+ reportAttributes,
+ currentReportsToDisplay,
+ shouldUseNarrowLayout,
+ accountID,
+ currentReportIDValue,
+ derivedCurrentReportID,
+ prevDerivedCurrentReportID,
+ policyMemberAccountIDs,
+ prevBetas,
+ prevPriorityMode,
+ reportsToDisplayInLHN,
+ orderedReportIDs,
+ orderedReports,
+ };
+ const prevContextValue = usePrevious(contextValue);
+ const previousDeps = usePrevious(currentDeps);
+ const firstRender = useRef(true);
+
+ useEffect(() => {
+ // Cases below ensure we only log when the edge case (empty -> non-empty or non-empty -> empty) happens.
+ // This is done to avoid excessive logging when the orderedReports array is updated, but does not impact LHN.
+
+ // Case 1: orderedReports goes from empty to non-empty
+ if (contextValue.orderedReports.length > 0 && prevContextValue?.orderedReports.length === 0) {
+ logChangedDeps('[useSidebarOrderedReports] Ordered reports went from empty to non-empty', currentDeps, previousDeps);
+ }
+ // Case 2: orderedReports goes from non-empty to empty
+ if (contextValue.orderedReports.length === 0 && prevContextValue?.orderedReports.length > 0) {
+ logChangedDeps('[useSidebarOrderedReports] Ordered reports went from non-empty to empty', currentDeps, previousDeps);
+ }
+
+ // Case 3: orderedReports are empty from the beginning
+ if (firstRender.current && contextValue.orderedReports.length === 0) {
+ logChangedDeps('[useSidebarOrderedReports] Ordered reports initialized empty', currentDeps, previousDeps);
+ }
+
+ firstRender.current = false;
+ });
+
return {children};
}
@@ -233,3 +282,31 @@ function useSidebarOrderedReports() {
export {SidebarOrderedReportsContext, SidebarOrderedReportsContextProvider, useSidebarOrderedReports};
export type {PartialPolicyForSidebar, ReportsToDisplayInLHN};
+
+function getChangedKeys>(deps: T, prevDeps: T) {
+ const depsKeys = Object.keys(deps);
+
+ return depsKeys.filter((depKey) => !deepEqual(deps[depKey], prevDeps[depKey]));
+}
+
+function logChangedDeps>(msg: string, deps: T, prevDeps: T) {
+ const startTime = performance.now();
+ const changedDeps = getChangedKeys(deps, prevDeps);
+ const parsedDeps = parseDepsForLogging(deps);
+ const processingDuration = performance.now() - startTime;
+ Log.info(msg, false, {
+ deps: parsedDeps,
+ changedDeps,
+ processingDuration,
+ });
+}
+
+/**
+ * @param deps - The dependencies to parse.
+ * @returns A simplified object with light-weight values.
+ */
+function parseDepsForLogging>(deps: T) {
+ // If object or array, return the keys' length
+ // If primitive, return the value
+ return Object.fromEntries(Object.entries(deps).map(([key, value]) => [key, typeof value === 'object' && value !== null ? Object.keys(value).length : value]));
+}