visgl / visgl/react-map-gl

[Bug] Marker crashes with "appendChild" on Activity reappear when Next.js `cacheComponents` is enabled (production-only)

Open
#2,588 0 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
8.5k
Forks
1.4k
Avg merge
5d 17h
Merged PRs (30d)
3

Description

Description

Related to #2584 but a distinct root cause, not a rapid navigation race condition. This crash occurs on a single normal navigation when cacheComponents: true is enabled in Next.js 16, and only in production builds (Webpack). Never reproduces in dev mode (Turbopack).

When Next.js cacheComponents: true is enabled, routes are wrapped in React's <Activity> component. Activity runs useEffect cleanups on hide (navigation away) and re-runs effects on reappear (navigation back).

The Map component's cleanup calls mapbox.destroy()map.remove(), which sets _container = null and _removed = true on the Mapbox instance. When Activity reappears the route, Marker's useEffect re-fires and calls marker.addTo(map.getMap()). However, map.getMap() returns the destroyed instance with _container = null, resulting in a crash.

Unlike #2584 where _container exists but child elements are partially torn down, here _container is fully null because map.remove() ran to completion during the Activity hide phase.

Expected Behavior

Map and Marker components should reinitialize cleanly when Activity reappears the route. The Mapbox instance should be recreated after it was destroyed during the hide phase.

Steps to Reproduce
  1. Create a Next.js 16 app with cacheComponents: true in next.config.ts.
  2. Create a page with <Map> and <Marker> components from react-map-gl.
  3. Build for production (next build && next start) - this does not reproduce in dev mode.
  4. Navigate to the map page → renders fine ✅.
  5. Navigate away to any other route.
  6. Navigate back to the map page.

Crash on second visit:

TypeError: Cannot read properties of undefined (reading 'appendChild')
    at Marker.addTo
    at recursivelyTraverseReappearLayoutEffects

The stack trace recursivelyTraverseReappearLayoutEffects confirms React Activity's reappear phase is the trigger, not a standard remount.

Environment
  • Framework version: react-map-gl@8.1.0 (via @vis.gl/react-mapbox)
  • Map library: mapbox-gl@3.x
  • Next.js: 16 (App Router, cacheComponents: true, production/Webpack only)
  • React: 19
  • Browser: Chrome
  • OS: Windows 11
Logs
TypeError: Cannot read properties of undefined (reading 'appendChild')
    at Marker.addTo (mapbox-gl)
    at eval (marker.ts — useEffect calling marker.addTo(map.getMap()))
    at recursivelyTraverseReappearLayoutEffects (react-dom)
    at reappearLayoutEffects (react-dom)

Confirmed via instrumentation:

  • map.getMap() returns the Mapbox instance ✅ (truthy)
  • map.getMap()._removed === true ❌ (destroyed during Activity hide)
  • map.getMap()._container === null ❌ (set to null by map.remove())

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in marker.ts, focusing on the useEffect that calls marker.addTo(map.getMap()), then trace the Map cleanup through mapbox.destroy() and map.remove(). Reproduce with a production Next.js 16 build using cacheComponents: true, and verify that navigating away and back recreates the Mapbox instance without the appendChild crash during Activity reappearance.

Written by the indexing model from the issue text.

Assessment

Tech stack
next.js, react, typescript
Domain
frontend, web-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.