Skip to content

fix: prevent rapid double-tap from pushing duplicate history entries#442

Merged
Junman140 merged 1 commit into
Pi-Defi-world:devfrom
Sundayabel222:fix/mobile-nav-race-condition
Jun 1, 2026
Merged

fix: prevent rapid double-tap from pushing duplicate history entries#442
Junman140 merged 1 commit into
Pi-Defi-world:devfrom
Sundayabel222:fix/mobile-nav-race-condition

Conversation

@Sundayabel222
Copy link
Copy Markdown
Contributor

@Sundayabel222 Sundayabel222 commented Jun 1, 2026

Closes #328

Problem

Rapidly tapping two nav tabs in succession can push two routes onto the history stack before the first one completes, corrupting the back-button history on mobile.

Root Cause

The previous useTransition guard was insufficient — isPending is an async React state update. A second tap could arrive before React re-renders with isPending=true, and there was no synchronous lock preventing the second router.push from executing.

Fix (components/mobile-nav.tsx)

  • Replaced <Link> with <button> + handleNav() handler for full navigation control
  • Synchronous ref-based lock (navigatingTo) is set on click and only cleared when pathname actually changes (via useEffect), preventing any second navigation while one is in-flight
  • useTransition provides the isPending flag to visually disable buttons during navigation
  • pathname === href guard skips re-pushing the current page
  • Preserves existing features: visualViewport keyboard handling, tabIndex ordering, icon wrapping

Closes #328

Summary by CodeRabbit

  • Improvements
    • Mobile navigation now prevents accidental duplicate navigation attempts while transitions are in progress, enhancing overall navigation reliability and responsiveness.

The useTransition guard alone was insufficient because isPending is an
async state update — a second tap could arrive before React re-renders.
A ref-based lock (set synchronously on click, cleared only when pathname
actually changes via useEffect) ensures no second navigation can start
while one is in-flight.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

MobileNav switches from Next.js <Link> navigation to programmatic useRouter().push() guarded by transition state and a ref-tracked target route, preventing duplicate navigations on rapid successive taps. Buttons are disabled while navigation is pending.

Changes

Mobile Navigation Race Condition Prevention

Layer / File(s) Summary
Pending state and navigation guard logic
components/mobile-nav.tsx
useRouter and useTransition hooks are added; a navigatingTo ref tracks the in-flight target route and is cleared whenever pathname changes; handleNav guards against navigating while pending or re-navigating to an already-targeted route, performing the push inside startTransition.
Button-based navigation with disabled state
components/mobile-nav.tsx
Nav items switch from <Link> wrappers to <button> elements, each calling handleNav(item.href) on click; buttons are disabled={isPending} to prevent interaction during navigation; accessibility attributes and tab indexing remain intact.

Possibly related PRs

  • Pi-Defi-world/acbu-frontend#428: Both PRs touch components/mobile-nav.tsx's mobile nav item rendering with respect to keyboard/tab focus order—main PR preserves the existing tabIndex behavior while changing the click/navigation mechanism from <Link> to guarded router.push.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 Fast fingers tapping twice no more,
A guardian ref guards the door,
With transitions smooth and buttons still,
We bounce back once, as back should will!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main fix: preventing duplicate history entries from rapid double-taps, which is the core problem solved in the changeset.
Linked Issues check ✅ Passed The code changes fully address issue #328 by implementing a synchronous ref-based lock (navigatingTo) to prevent concurrent navigations while useTransition handles visual feedback.
Out of Scope Changes check ✅ Passed All changes in components/mobile-nav.tsx are directly scoped to fixing the navigation race condition; no unrelated modifications were introduced.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/mobile-nav.tsx`:
- Around line 33-35: The lock (navigatingTo.current) is only cleared inside the
pathname useEffect, so if a push is interrupted and the URL doesn't change it
stays non-null; modify the navigation handler(s) that set navigatingTo.current
(e.g., the tap/click handler that calls router.push or navigate) to always clear
navigatingTo.current in a finally block after the navigation promise settles,
and add a short fallback timeout (e.g., 2–5s) to reset navigatingTo.current to
null if the navigation neither resolves nor changes pathname; keep the existing
useEffect([pathname]) clear as well for the normal case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ddc94b56-4928-42db-9125-509f592ae539

📥 Commits

Reviewing files that changed from the base of the PR and between 5041fcb and b1798bd.

📒 Files selected for processing (1)
  • components/mobile-nav.tsx

Comment thread components/mobile-nav.tsx
@Junman140 Junman140 merged commit 777a67b into Pi-Defi-world:dev Jun 1, 2026
1 of 2 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jun 2, 2026
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.

useRouter race condition on fast double-navigation – M

2 participants