You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: contributingGuides/PERFORMANCE.md
+20-1Lines changed: 20 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -336,10 +336,29 @@ Once potential performance bottlenecks are identified, the next step is to optim
336
336
* Components performing heavy calculations or processing large datasets.
337
337
* Components subscribing directly to frequently changing data instead of receiving it as props from a parent.
338
338
* Incorrect or inefficient use of memoization techniques (`React.memo`, `useMemo`, `useCallback`).
339
-
* Rendering of unnecessary or duplicated child components.
339
+
*[Rendering of unnecessary or duplicated child components](#rendering-of-unnecessary-or-duplicated-child-components).
340
340
341
341
After implementing optimizations, it's crucial to validate the changes. Manual comparison of performance metrics can be tedious and prone to bias. It's highly recommended to use tools that allow forobjective comparison of traces or metrics before and after changes. This helpsin confirming actual performance gains and avoiding regressions in other areas.
342
342
343
343
The optimization process is often iterative. Small, incremental improvements can accumulate to significant overall gains. When proposing changes, aim for self-contained and predictable modifications to facilitate review and discussion.
344
344
345
345
Finally, before concluding an investigation, always validate improvements against real-world scenarios. This includes testing on different platforms and with various build configurations (e.g., production builds) to ensure the optimizations hold up in diverse environments. Remember that performance maintenance is a continuous effort, encompassing not just profiling but also adherence to code conventions and real user monitoring.
346
+
347
+
## Common performance bottlenecks
348
+
### Rendering of unnecessary or duplicated child components
349
+
Since our codebase is very complex, it results in a large DOM tree rendered for the user. This may become a potential performance issue if not handled carefully.
350
+
351
+
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.
352
+
353
+
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.
354
+
355
+
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 desktop/web) is included.
356
+
357
+
The last common issue is related to the use of `return null`. Sometimes we already know in the parent component that a specific child should not be rendered. In such cases, we unnecessarily execute the child's internal logic (calling hooks, sending requests) only to find out that the whole process was redundant.
358
+
359
+
Examples:
360
+
- [Add shouldRender check in EducationalTooltip to avoid unnecessary calls](https://github.com/Expensify/App/pull/66052) - avoids rendering invisible components
361
+
- [Remove shouldAdjustScrollView to avoid heavy rerender](https://github.com/Expensify/App/pull/66849) - removes hooks that were called only for Safari logic slowing down the `ReportScreen.tsx`
362
+
- [PopoverWithMeasuredContent optimization for mobile](https://github.com/Expensify/App/pull/68223) - returns early to avoid unnecessary calculations
363
+
- [Reduce confirm modal initial render count](https://github.com/Expensify/App/pull/67518) - returns early to reduce first load cost
364
+
- [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
0 commit comments