Skip to content

[HOLD for payment 2024-01-03] [HOLD for payment 2023-12-28] [Performance] Search input performance optimization #32806

Description

@mountiny

Coming from this performance proposal:

Problem:

Currently, when users type in the search input in Money Request Participant List search, each keystroke triggers re-rendering of Option List, which is preceded by heavy calculations in the getOptions function, leading to significant performance overhead. Comparing the execution time of this function on Web:

  • Account with 66 reports and 4200 personal details → 45ms
  • Account with 15330 reports and 12 personal details → 650ms

With keystrokes calling such expensive function, this results in a laggy user experience, as the app processes each input individually without any delay or optimization. The continuous processing of these inputs strains the app’s resources, causing slowdowns and delays in displaying search results.

Additionally, each keystroke is causing unnecessary re-renders in the list items that could be avoided to reduce the consumption of the CPU.

### Solution:
To address this problem, we could do a few steps that should positively impact the usage of search:

  1. Debouncing the search value update - this will allow to call expensive calculations only after the user stopped typing for a specified duration (e.g. 200 ms). So, when typing “Andrew”, the getOptions would run only once instead of 6 times (unless there will be a pause while typing)
  2. Memoizing components to avoid unnecessary re-renders - currently, when typing in the input, a lot of components are getting unnecessarily re-rendered - e.g. each list item and BaseOptionSelector. Memoizing BaseOptionsSelector and fixing wrong memo condition !_.isEqual(prevProps.option.icons, nextProps.option.icons) causing re-renders on each keystroke.
  3. We could stop using debounce on search in server, since with a debounced search value update it won’t be necessary anymore.

Comparing the results on the account with 15330 reports on Web:
Action: write adg in the search
Metric: getOptions call count Before: 4 After: 1
Metric: max JS heap Before: 595mb After: 306mb
Metric: MoneyRequestParticipantSelector max render time Before: ~110ms After: ~75ms
Metric: Single list item render count Before: 4 After: 1

Comparing account with 4200 personal details on Android - you can see attached screenshot of CPU usage from Flashlight. The blue line indicates the CPU usage while writing my email address “tomasz.misiukiewicz@callstack.com” and having getOptions method called on each keystroke. CPU usage for JS thread is around 100% all the time. The yellow line indicates CPU usage when calling getOptions function is debounced - the usage jumps only when there was a pause in typing longer than the debounce time.

This changes will also benefit other lists using OptionsSelector component:

  • CategoryPicker
  • TagPicker
  • NewChatPage
  • SearchPage
  • TaskAssigneeSelectorModal
  • TaskShareDestinationSelectorModal

Few of them already have debouncing implemented, but they have different amount of milliseconds set, so we can unify them. Additionally each one of them will benefit from reduced amount of re-renders of list items.

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.WeeklyKSv2

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions