Skip to content

Commit 9d5f213

Browse files
authored
Merge pull request Expensify#65923 from callstack-internal/fix/lhn-empty-edge-case
[NoQA] Log useSidebarOrderedReports dependencies at empty edge cases
2 parents 5d665f9 + 4c4835c commit 9d5f213

1 file changed

Lines changed: 78 additions & 1 deletion

File tree

src/hooks/useSidebarOrderedReports.tsx

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import React, {createContext, useCallback, useContext, useEffect, useMemo, useState} from 'react';
1+
import {deepEqual} from 'fast-equals';
2+
import React, {createContext, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
23
import type {OnyxEntry} from 'react-native-onyx';
4+
import Log from '@libs/Log';
35
import {getPolicyEmployeeListByIdWithoutCurrentUser} from '@libs/PolicyUtils';
46
import SidebarUtils from '@libs/SidebarUtils';
57
import CONST from '@src/CONST';
@@ -224,6 +226,53 @@ function SidebarOrderedReportsContextProvider({
224226
};
225227
}, [getOrderedReportIDs, orderedReportIDs, derivedCurrentReportID, policyMemberAccountIDs, shouldUseNarrowLayout, getOrderedReports, orderedReports]);
226228

229+
const currentDeps = {
230+
priorityMode,
231+
chatReports,
232+
policies,
233+
transactions,
234+
transactionViolations,
235+
reportNameValuePairs,
236+
betas,
237+
reportAttributes,
238+
currentReportsToDisplay,
239+
shouldUseNarrowLayout,
240+
accountID,
241+
currentReportIDValue,
242+
derivedCurrentReportID,
243+
prevDerivedCurrentReportID,
244+
policyMemberAccountIDs,
245+
prevBetas,
246+
prevPriorityMode,
247+
reportsToDisplayInLHN,
248+
orderedReportIDs,
249+
orderedReports,
250+
};
251+
const prevContextValue = usePrevious(contextValue);
252+
const previousDeps = usePrevious(currentDeps);
253+
const firstRender = useRef(true);
254+
255+
useEffect(() => {
256+
// Cases below ensure we only log when the edge case (empty -> non-empty or non-empty -> empty) happens.
257+
// This is done to avoid excessive logging when the orderedReports array is updated, but does not impact LHN.
258+
259+
// Case 1: orderedReports goes from empty to non-empty
260+
if (contextValue.orderedReports.length > 0 && prevContextValue?.orderedReports.length === 0) {
261+
logChangedDeps('[useSidebarOrderedReports] Ordered reports went from empty to non-empty', currentDeps, previousDeps);
262+
}
263+
// Case 2: orderedReports goes from non-empty to empty
264+
if (contextValue.orderedReports.length === 0 && prevContextValue?.orderedReports.length > 0) {
265+
logChangedDeps('[useSidebarOrderedReports] Ordered reports went from non-empty to empty', currentDeps, previousDeps);
266+
}
267+
268+
// Case 3: orderedReports are empty from the beginning
269+
if (firstRender.current && contextValue.orderedReports.length === 0) {
270+
logChangedDeps('[useSidebarOrderedReports] Ordered reports initialized empty', currentDeps, previousDeps);
271+
}
272+
273+
firstRender.current = false;
274+
});
275+
227276
return <SidebarOrderedReportsContext.Provider value={contextValue}>{children}</SidebarOrderedReportsContext.Provider>;
228277
}
229278

@@ -233,3 +282,31 @@ function useSidebarOrderedReports() {
233282

234283
export {SidebarOrderedReportsContext, SidebarOrderedReportsContextProvider, useSidebarOrderedReports};
235284
export type {PartialPolicyForSidebar, ReportsToDisplayInLHN};
285+
286+
function getChangedKeys<T extends Record<string, unknown>>(deps: T, prevDeps: T) {
287+
const depsKeys = Object.keys(deps);
288+
289+
return depsKeys.filter((depKey) => !deepEqual(deps[depKey], prevDeps[depKey]));
290+
}
291+
292+
function logChangedDeps<T extends Record<string, unknown>>(msg: string, deps: T, prevDeps: T) {
293+
const startTime = performance.now();
294+
const changedDeps = getChangedKeys(deps, prevDeps);
295+
const parsedDeps = parseDepsForLogging(deps);
296+
const processingDuration = performance.now() - startTime;
297+
Log.info(msg, false, {
298+
deps: parsedDeps,
299+
changedDeps,
300+
processingDuration,
301+
});
302+
}
303+
304+
/**
305+
* @param deps - The dependencies to parse.
306+
* @returns A simplified object with light-weight values.
307+
*/
308+
function parseDepsForLogging<T extends Record<string, unknown>>(deps: T) {
309+
// If object or array, return the keys' length
310+
// If primitive, return the value
311+
return Object.fromEntries(Object.entries(deps).map(([key, value]) => [key, typeof value === 'object' && value !== null ? Object.keys(value).length : value]));
312+
}

0 commit comments

Comments
 (0)