Files
igny8/ROUTER-HOOK-ERROR-ROOT-CAUSE.md
2025-12-10 13:58:13 +00:00

5.3 KiB

Router Hook Error - ROOT CAUSE ANALYSIS (SOLVED)

Date: December 10, 2025

The Errors (FIXED)

  • /automationuseNavigate() may be used only in the context of a <Router> component. FIXED
  • /planner/keywordsuseLocation() may be used only in the context of a <Router> component. FIXED
  • /planner/clustersuseLocation() may be used only in the context of a <Router> component. FIXED

ROOT CAUSE: Vite Bundling Multiple React Router Chunks

The Real Problem

Components imported Router hooks from TWO different packages:

  • Some used import { useLocation } from 'react-router'
  • Some used import { useLocation } from 'react-router-dom'
  • main.tsx used import { BrowserRouter } from 'react-router-dom'

Even though npm showed both packages as v7.9.5 and "deduped", Vite bundled them into SEPARATE chunks:

chunk-JWK5IZBO.js  ← Contains 'react-router' code
chunk-U2AIREZK.js  ← Contains 'react-router-dom' code

Why This Caused the Error

  1. BrowserRouter from 'react-router-dom' (chunk-U2AIREZK.js) creates a Router context
  2. useLocation() from 'react-router' (chunk-JWK5IZBO.js) tries to read Router context
  3. Different chunks = Different module instances = Different React contexts
  4. The context from chunk-U2AIREZK is NOT accessible to hooks in chunk-JWK5IZBO
  5. Hook can't find context → Error: "useLocation() may be used only in the context of a component"

Evidence from Error Stack

ErrorBoundary caught an error: Error: useLocation() may be used only in the context of a <Router> component.
    at useLocation (chunk-JWK5IZBO.js?v=f560299f:5648:3)   'react-router' chunk
    at TablePageTemplate (TablePageTemplate.tsx:182:20)
    ...
    at BrowserRouter (chunk-U2AIREZK.js?v=f560299f:9755:3)   'react-router-dom' chunk

Two different chunks = Context mismatch!

Component Stack Analysis

The error showed BrowserRouter WAS in the component tree:

TablePageTemplate (useLocation ERROR)
  ↓ Clusters
  ↓ ModuleGuard  
  ↓ Routes
  ↓ App
  ↓ BrowserRouter ← Context provided HERE

Router context was available, but the hook was looking in the WRONG chunk's context.

The Fix Applied

1. Changed ALL imports to use 'react-router-dom'

Files updated (16 files):

  • src/templates/TablePageTemplate.tsx
  • src/templates/ContentViewTemplate.tsx
  • src/components/navigation/ModuleNavigationTabs.tsx
  • src/components/common/DebugSiteSelector.tsx
  • src/components/common/SiteSelector.tsx
  • src/components/common/SiteAndSectorSelector.tsx
  • src/components/common/PageTransition.tsx
  • src/pages/Linker/ContentList.tsx
  • src/pages/Linker/Dashboard.tsx
  • src/pages/Writer/ContentView.tsx
  • src/pages/Writer/Content.tsx
  • src/pages/Writer/Published.tsx
  • src/pages/Writer/Review.tsx
  • src/pages/Optimizer/ContentSelector.tsx
  • src/pages/Optimizer/AnalysisPreview.tsx
  • src/pages/Optimizer/Dashboard.tsx

Changed:

// BEFORE
import { useLocation } from 'react-router';
import { useNavigate } from 'react-router';

// AFTER
import { useLocation } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';

2. Removed 'react-router' from package.json

Before:

{
  "dependencies": {
    "react-router": "^7.1.5",
    "react-router-dom": "^7.9.5"
  }
}

After:

{
  "dependencies": {
    "react-router-dom": "^7.9.5"
  }
}

3. Result

Now Vite bundles ALL Router code into a SINGLE chunk, ensuring Router context is shared across all components.

Why Container Rebuild "Fixed" It Temporarily

When you rebuild containers, sometimes Vite's chunk splitting algorithm temporarily bundles both packages together, making the error disappear. But on the next HMR or rebuild, it splits them again → error returns.

Testing Instructions

After these changes, test by visiting:

Check browser console for zero Router-related errors.

Key Learnings

  1. npm deduplication ≠ Vite bundling - Even if npm shows packages as "deduped", Vite may still create separate chunks
  2. Module bundler matters - The error wasn't in React or React Router, it was in how Vite split the code
  3. Import source determines chunk - Importing from different packages creates different chunks with separate module instances
  4. React Context is per-module-instance - Contexts don't cross chunk boundaries
  5. Consistency is critical - ALL imports must use the SAME package to ensure single chunk
  6. Component stack traces reveal bundling - Looking at chunk file names in errors shows the real problem

Solution: Use ONE Package Consistently

For React Router v7 in Vite projects:

  • Use 'react-router-dom' exclusively
  • Never mix 'react-router' and 'react-router-dom' imports
  • Remove unused router packages from package.json
  • Verify with: grep -r "from 'react-router'" src/ (should return nothing)

Status: RESOLVED

All imports standardized to 'react-router-dom'. Error should no longer occur after HMR, container restarts, or cache clears.