Migrate SearchAutocompleteList to useFilteredOptions#85922
Migrate SearchAutocompleteList to useFilteredOptions#85922hoangzinh wants to merge 5 commits intoExpensify:mainfrom
Conversation
Replace useOptionsList context hook with useFilteredOptions to eliminate
unnecessary background recalculations on personal details/reports changes.
Key changes:
- Replace useOptionsList() with useFilteredOptions({enabled: true})
- Remove OptionsListStateContext dependency
- Update cold start telemetry to use isLoading from hook
- Add emptyOptionList fallback for null options
- Rename listOptions and isLoadingFullData to avoid conflicts
Part of OptionListContextProvider removal effort.
Fixes Expensify#82187
Use isLoading directly instead of areOptionsInitialized: !isLoading for clearer intent and simpler code in skeleton span attributes.
…-to-usefiltered-options
|
@shubham1206agra Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d749d89e90
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const taxRates = getAllTaxRates(policies); | ||
|
|
||
| const {options, areOptionsInitialized} = useOptionsList(); | ||
| const {options: listOptions, isLoading} = useFilteredOptions({enabled: true, searchTerm: autocompleteQueryValue, betas: betas ?? []}); |
There was a problem hiding this comment.
Debounce searchTerm passed to useFilteredOptions
Passing autocompleteQueryValue directly into useFilteredOptions here causes a full option-list rebuild on every keystroke; useFilteredOptions memoizes on searchTerm and calls createFilteredOptionList whenever it changes (src/hooks/useFilteredOptions.ts, lines 84-95), which reprocesses the reports/personal-details collections. In Search Router this turns normal typing into repeated full-list recomputation for high-traffic accounts, introducing visible input lag/jank compared to the previous flow that reused precomputed options and only filtered them.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
@shubham1206agra, instead of passing searchTerm, should we pass a boolean flag so full option-list won't rebuild on every keystore? Wdyt
Replace searchTerm string parameter with isSearching boolean flag in useFilteredOptions and createFilteredOptionList to prevent full option-list rebuilds on every keystroke. The boolean flag only changes when transitioning between empty/non-empty states, instead of on every character typed. This fixes the P1 performance issue where passing autocompleteQueryValue directly caused visible input lag for high-traffic accounts. Addresses PR review comment #2965259765
|
PR doesn’t need product input as a migration PR. Unassigning and unsubscribing myself. |
| enabled: didScreenTransitionEnd, | ||
| betas: betas ?? [], | ||
| searchTerm: debouncedTextInputValue, | ||
| isSearching: !!debouncedTextInputValue, |
| batchSize: 100, | ||
| enablePagination: true, | ||
| searchTerm: debouncedSearchTerm, | ||
| isSearching: !!debouncedSearchTerm, |
Explanation of Change
Replace useOptionsList context hook with useFilteredOptions to eliminate unnecessary background recalculations on personal details/reports changes.
Part of OptionListContextProvider removal effort.
Fixed Issues
$ #82187
PROPOSAL:
Tests
Same as QA
Offline tests
Same as QA
QA Steps
// TODO: These must be filled out, or the issue title must include "[No QA]."
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Screen.Recording.2026-03-20.at.18.05.40.mov
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Screen.Recording.2026-03-20.at.17.56.59.web.mov