Skip to content

Fix console error when opening a newly created expense on the Spend page#95670

Open
MelvinBot wants to merge 1 commit into
mainfrom
claude-fixSearchRenderPhaseSetStateWarning
Open

Fix console error when opening a newly created expense on the Spend page#95670
MelvinBot wants to merge 1 commit into
mainfrom
claude-fixSearchRenderPhaseSetStateWarning

Conversation

@MelvinBot

Copy link
Copy Markdown
Contributor

Explanation of Change

Fixes the dev-only console error Cannot update a component (SearchPage) while rendering a different component (Search) that appears when opening a newly created expense on the Spend page.

Search bails out to an error/empty state via conditional returns during render (searchResults === undefined, hasErrors, and the empty-state branch). Each of those calls cancelNavigationSpans(), which — before this change — also called the parent-owned onContentReady?.() (SearchPage's setIsSearchReady(true) from useSearchOverlay). Updating the parent's state during Search's render is exactly what React's warning flags.

When a just-created expense is opened before its transaction lands in the search snapshot, Search transiently takes the empty-state bail-out, so the render-phase parent update fires and the warning is logged.

The fix moves the onContentReady?.() call out of cancelNavigationSpans and into the existing no-dependency post-commit useEffect (guarded by the didBailToFallbackState ref that the bail-out paths already set). This defers the parent update to the commit phase instead of during render, matching the flush pattern already used in the same file. setIsSearchReady(true) is idempotent, so firing it on every bail-out render is safe and does not loop. Behavior is otherwise unchanged.

Fixed Issues

$ #94318
PROPOSAL: #94318 (comment)

Tests

// TODO: The human co-author must fill out the tests you ran before marking this PR as "ready for review"
// Please describe what tests you performed that validates your changed worked.

  • Verify that no errors appear in the JS console

Offline tests

Same as Tests.

QA Steps

// TODO: The human co-author must fill out the QA tests you ran before marking this PR as "ready for review".
// Please describe what QA needs to do to validate your changes and what areas do they need to test for regressions.

  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I followed proper code patterns (see Reviewing the code)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari

Co-authored-by: DylanDylann <DylanDylann@users.noreply.github.com>
@MelvinBot MelvinBot requested a review from a team July 9, 2026 09:25
@MelvinBot

Copy link
Copy Markdown
Contributor Author

I created this PR from an upstream branch since I don't have push access to your fork.

To take ownership of this branch and be able to push updates, run:

git remote add upstream https://github.com/Expensify/App.git
git fetch upstream claude-fixSearchRenderPhaseSetStateWarning
git checkout -b claude-fixSearchRenderPhaseSetStateWarning upstream/claude-fixSearchRenderPhaseSetStateWarning
git push -u origin claude-fixSearchRenderPhaseSetStateWarning

Then you can close this PR and open a new one from your fork.

@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ Changes either increased or maintained existing code coverage, great job!

Files with missing lines Coverage Δ
src/components/Search/index.tsx 46.07% <75.00%> (+0.01%) ⬆️
... and 11 files with indirect coverage changes

@MelvinBot

Copy link
Copy Markdown
Contributor Author

DylanDylann — no code fix is needed. The only genuinely failing check is PR Author Checklist / checklist, and it's failing for a non-code reason: the PR body's author-checklist boxes are all unchecked and the Tests / QA Steps sections still contain the // TODO placeholders left for the human co-author.

Per MelvinBot policy I can't tick the author checklist or fill out the human Tests/QA sections on your behalf — so this check will stay red until you complete it. That's the "fix": edit the PR description to fill in the Tests/QA steps and check the author-checklist items.

Every code-relevant check is green. I verified the two most likely to catch this change locally against the changed file (src/components/Search/index.tsx):

  • ESLint: PASS (0 errors). The useEffect that now calls onContentReady?.() intentionally has no dependency array, so react-hooks/exhaustive-deps doesn't apply, and the cancelNavigationSpans useCallback correctly dropped onContentReady from its deps since it no longer references it.
  • typecheck: PASS (0 errors project-wide). onContentReady is an existing optional prop already invoked elsewhere in the file, so the moved call is type-safe.

All other CI jobs are passing. When I finished, ESLint check and build (Debug, true) were still queued/running (not failed) — both are expected to pass, as this is a one-line render-phase refactor with no native or lint impact.

The failing check log
You completed 0 out of 38 checklist items with 38 unfinished items
##[error]PR Author Checklist is not completely filled out. Please check every box to verify you've thought about the item.

@DylanDylann

Copy link
Copy Markdown
Contributor

@MelvinBot Ready to review

@MelvinBot

Copy link
Copy Markdown
Contributor Author

Review

Verdict: The code change is correct, minimal, and the root-cause reasoning holds up — the render-phase → commit-phase move is the right fix for this warning. No functional regression. Two non-code items still block merge (see below); I can't complete them myself.

Why the fix is correct

The warning fires because Search updates its parent (SearchPage) during its own render. The bail-out paths — searchResults === undefined, hasErrors, and the empty-state branch — all call cancelNavigationSpans() inside conditional returns (render phase). Moving onContentReady?.() out of that callback and into the post-commit dep-free effect defers the parent update to the commit phase, which is exactly what React wants.

I verified the supporting claims:

  • Idempotency: onContentReady resolves to onSearchContentReadysetIsSearchReady(true). Setting the same true value bails out of re-render, so firing it on every bail-out render is safe and won't loop. ✅
  • Behavior equivalence: before this PR, onContentReady was already called unconditionally on every bail-out (just synchronously, in render). The dep-free effect runs after every commit and the didBailToFallbackState ref is set during the same bail-out render, so it still fires once per bail-out — just one commit later. ✅
  • Dependency change: dropping onContentReady from the cancelNavigationSpans useCallback deps is correct — it no longer references it. react-hooks/exhaustive-deps doesn't flag the effect since it intentionally has no dep array (pre-existing pattern in this file). ✅
  • Skeleton/deferred bail-outs (isDeferringHeavyWork, shouldShowRowSkeleton) don't call cancelNavigationSpans, so they don't trigger onContentReady — unchanged from before, and correct since those paths flush via their own onLayout. ✅

Blockers before this can merge

  1. PR Author Checklist is failing because the checklist boxes are all unchecked and the Tests / QA Steps sections still contain the // TODO placeholders. Per policy I can't tick the author checklist or fill the human Tests/QA sections — a human co-author must do this. Since the repro is a dev-only console error, the natural QA step is the issue's own flow: create a workspace expense → immediately open it on the Spend page → confirm no Cannot update a component (SearchPage) while rendering a different component (Search) error in the console.

  2. No regression test. This is genuinely hard to unit-test (it's a dev-mode console.error), so I'd treat it as optional rather than a hard blocker — but if feasible, a test that renders Search in the transient empty-state and asserts console.error was not called with the render-phase warning would guard against re-introduction. Worth a note in the checklist either way.

Every code-relevant check is green (ESLint + typecheck verified locally earlier). Once the checklist/Tests/QA are filled in, this looks good to go from a code standpoint.

@DylanDylann

Copy link
Copy Markdown
Contributor

@MelvinBot Mark the PR ready

@MelvinBot MelvinBot marked this pull request as ready for review July 9, 2026 09:49
@MelvinBot MelvinBot requested a review from a team as a code owner July 9, 2026 09:49
@melvin-bot melvin-bot Bot requested review from DylanDylann and heyjennahay and removed request for a team July 9, 2026 09:49
@melvin-bot

melvin-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

@DylanDylann 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]

@melvin-bot melvin-bot Bot removed the request for review from a team July 9, 2026 09:50
@MelvinBot

Copy link
Copy Markdown
Contributor Author

Done — PR #95670 is now marked Ready for review. ✅

One heads-up: the PR Author Checklist / checklist check will stay red until the author-checklist boxes are checked and the Tests / QA Steps sections (still // TODO placeholders) are filled in. Per policy I can't tick the checklist or complete the human Tests/QA sections on your behalf, so that last step is on the human co-author before this can merge.

@MelvinBot

Copy link
Copy Markdown
Contributor Author

The failing ESLint check is not related to this PR — it's a pre-existing eslint-seatbelt baseline drift on main, so I have not pushed a change to this branch.

Why it's unrelated: This PR only touches src/components/Search/index.tsx, which lints clean. All 31 reported errors are in two files this PR never touches:

  • src/libs/actions/Report/index.tsno-restricted-syntax (namespace imports): 10 errors, baseline allows 9
  • tests/actions/IOUTest/SplitTest.ts@typescript-eslint/no-unsafe-type-assertion: 21 errors, baseline allows 20

Both files have the exact same violation counts on main (origin/main = 7f29834) as on this branch, and the committed baseline in config/eslint/eslint.seatbelt.tsv is byte-identical between the two. In other words, main itself is currently over its lint baseline — a PR merged an extra namespace import to Report/index.ts and an extra unsafe assertion to SplitTest.ts without regenerating the seatbelt baseline, and CI enforces it repo-wide, so every open PR is failing this check, not just this one.

Merging latest main won't help — main's tip is still drifted.

Recommended fix (belongs on main, not this PR): either resolve the two actual violations, or regenerate the seatbelt baseline (npm run lint locally updates config/eslint/eslint.seatbelt.tsv to the real counts) and merge that. I deliberately did not bundle that unrelated baseline edit into this focused Search bugfix.

Evidence
# Files changed by this PR (vs origin/main)
src/components/Search/index.tsx   ← only real code change
package.json / package-lock.json / *.plist / build.gradle / Mobile-Expensify  ← version bumps from main merge

# origin/main Report/index.ts namespace imports: 10  (baseline in seatbelt.tsv: 9)
# origin/main SplitTest.ts unsafe assertions:    21  (baseline in seatbelt.tsv: 20)
# seatbelt.tsv lines 930 & 1772 identical on branch and origin/main

The other failing check, PR Author Checklist / checklist, is the standard author-checklist gate (needs a human to complete the checklist) — nothing to fix in code.

@DylanDylann

Copy link
Copy Markdown
Contributor

@MelvinBot Got a failed Eslint check

@DylanDylann

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: 0aa1d5923a

ℹ️ 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".

@MelvinBot

Copy link
Copy Markdown
Contributor Author

The failing ESLint check is not caused by this PR — it's a broken-main issue affecting every PR built right now. No action is needed on this branch.

What's failing: the seatbelt rule in src/libs/actions/Report/index.tsno-restricted-syntax reports 10 import * as … from '@libs/…' namespace imports, but the seatbelt baseline only allows 9. Since seatbelt runs frozen in CI, actual(10) > allowed(9) is a hard failure. This PR only touches src/components/Search/index.tsx and never goes near Report/index.ts.

Root cause: a recent revert on main reintroduced the 10th namespace import in Report/index.ts without bumping the seatbelt baseline. main is currently red on ESLint, so the failure is inherited by this branch.

Already being fixed: #95671"Fix ESLint seatbelt budget violations reintroduced by revert." Once that lands on main, merge main into this branch and the ESLint check will go green.

I'm not pushing anything here: the fix belongs on main (via #95671), not smuggled into this Search PR, and editing an unrelated file wouldn't unblock everyone else.

Evidence

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants