Skip to content

Commit 338c8a5

Browse files
Merge branch 'main' into jakubkalinski0/App_stuck_on_E_screen_after_refresh_on_confirm_odometer_page
2 parents 872259d + 5f60c77 commit 338c8a5

119 files changed

Lines changed: 3149 additions & 1719 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

babel.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ const metro = {
130130
production: {
131131
plugins: [['transform-remove-console', {exclude: ['error', 'warn']}]],
132132
},
133+
test: {
134+
plugins: ['@babel/plugin-transform-dynamic-import'],
135+
},
133136
},
134137
};
135138

contributingGuides/PERFORMANCE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ Since our codebase is very complex, it results in a large DOM tree rendered for
282282

283283
One of the most common issues is related to modals, popovers, and tooltips — elements that may appear on the screen. The problem is that they are usually present in the DOM tree even when initially invisible. Because of this, the initial render time of a screen may increase, ultimately slowing down the app.
284284

285-
The solution is better control of invisible elements, making sure they are not included in the first render. This can be done, e.g., by a simple `return null`, smart usage of `lazy loading`, the `useTransition` hook, or the `<Deferred />` component.
285+
The solution is better control of invisible elements, making sure they are not included in the first render. This can be done, e.g., by a simple `return null`, smart usage of `lazy loading`, the `useTransition` hook, or the [`<NavigationDeferredMount />`](/src/components/NavigationDeferredMount.tsx) component. `<NavigationDeferredMount />` gates a heavy subtree behind navigation transition completion via `TransitionTracker`, rendering a cheap `placeholder` until the nav animation has finished, then mounting its `children` inside `startTransition` — ideal for heavy subtrees (e.g. report headers, page-level secondary actions) mounted during navigation transitions that pull many `useOnyx` subscriptions or heavy hooks but don't need to be interactive on first render.
286286

287287
Another issue worth mentioning is unnecessary code execution, especially for elements that are never shown on a specific platform. In theory, we separate the logic between platforms by using index.tsx/index.native.tsx files, but sometimes platform-specific logic may slip in, causing unnecessary execution. For example, this may happen when logic specific to a wide layout (applicable only for web) is included.
288288

@@ -294,6 +294,7 @@ Examples:
294294
- [PopoverWithMeasuredContent optimization for mobile](https://github.com/Expensify/App/pull/68223) - returns early to avoid unnecessary calculations
295295
- [Reduce confirm modal initial render count](https://github.com/Expensify/App/pull/67518) - returns early to reduce first load cost
296296
- [Do not render PopoverMenu until it gets opened](https://github.com/Expensify/App/pull/67877) - adds a wrapper to control if `PopoverMenu` should be rendered
297+
- [Defer mount of MoneyReportHeaderSecondaryActions](https://github.com/Expensify/App/pull/88522) - introduces `NavigationDeferredMount` and uses it to defer the "More" dropdown subtree (20+ `useOnyx` subscriptions) until the navigation transition completes
297298

298299
# Proposing Performance Improvements
299300

docs/articles/travel/getting-started/Expensify-Travel-Walkthrough.md

Lines changed: 0 additions & 10 deletions
This file was deleted.

docs/redirects.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,7 @@ https://help.expensify.com/articles/new-expensify/reports-and-expenses/Delete-Ex
963963
https://help.expensify.com/articles/new-expensify/reports-and-expenses/Duplicate-Detection,https://help.expensify.com/articles/new-expensify/reports-and-expenses/How-to-Find-and-Resolve-Flagged-Duplicate-Expenses
964964
https://help.expensify.com/articles/new-expensify/reports-and-expenses/Merging-expenses,https://help.expensify.com/articles/new-expensify/reports-and-expenses/How-to-Merge-Expenses
965965
https://help.expensify.com/articles/new-expensify/reports-and-expenses/How-to-prevent-duplicate-expenses,https://help.expensify.com/articles/new-expensify/reports-and-expenses/Why-Expenses-Duplicate
966+
https://help.expensify.com/articles/travel/getting-started/Expensify-Travel-Walkthrough,https://help.expensify.com/travel/hubs/getting-started/
966967
https://help.expensify.com/articles/new-expensify/connect-credit-cards/Assign-and-Manage-Cards,https://help.expensify.com/articles/new-expensify/connect-credit-cards/Assign-Company-Cards
967968
https://help.expensify.com/articles/new-expensify/connect-credit-cards/Commercial-feeds,https://help.expensify.com/articles/new-expensify/connect-credit-cards/Set-up-a-Commercial-Card-Feed-Connection
968969
https://help.expensify.com/articles/new-expensify/connect-credit-cards/Company-Card-Settings,https://help.expensify.com/articles/new-expensify/connect-credit-cards/Configure-Company-Card-Settings

jest/setupAfterEnv.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
import '@testing-library/react-native';
2+
import type {KeyboardEventName} from 'react-native';
3+
import {Keyboard} from 'react-native';
24
import Onyx from 'react-native-onyx';
35
import ONYXKEYS from '@src/ONYXKEYS';
46

57
jest.useRealTimers();
68

9+
// Patch Keyboard.addListener to return a subscription object with .remove() so that
10+
// @react-navigation/bottom-tabs useIsKeyboardShown hook doesn't crash on cleanup.
11+
if (Keyboard && typeof Keyboard.addListener === 'function') {
12+
const originalAddListener = Keyboard.addListener.bind(Keyboard);
13+
Keyboard.addListener = ((event: KeyboardEventName, callback: () => void) => {
14+
const subscription = originalAddListener(event, callback);
15+
if (!subscription || typeof subscription.remove !== 'function') {
16+
return {remove: jest.fn()};
17+
}
18+
return subscription;
19+
}) as typeof Keyboard.addListener;
20+
}
21+
722
// This mock must live in setupAfterEnv (not setupFiles) because @shopify/flash-list/jestSetup,
823
// imported in setup.ts, registers its own measureLayout mock. Placing ours here ensures it
924
// runs after FlashList's setup and takes precedence.

0 commit comments

Comments
 (0)