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

156 lines
5.3 KiB
Markdown

# Router Hook Error - ROOT CAUSE ANALYSIS (SOLVED)
## Date: December 10, 2025
## The Errors (FIXED)
- `/automation``useNavigate() may be used only in the context of a <Router> component.` ✅ FIXED
- `/planner/keywords``useLocation() may be used only in the context of a <Router> component.` ✅ FIXED
- `/planner/clusters``useLocation() 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 <Router> component"
### Evidence from Error Stack
```javascript
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:**
```tsx
// 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:**
```json
{
"dependencies": {
"react-router": "^7.1.5",
"react-router-dom": "^7.9.5"
}
}
```
**After:**
```json
{
"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:
- https://app.igny8.com/planner/keywords → Should have NO errors
- https://app.igny8.com/planner/clusters → Should have NO errors
- https://app.igny8.com/automation → Should have NO errors
- https://app.igny8.com/account/plans → Should still have NO errors
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.