Skip to content

fix(navigation): keep the map and its follow camera through native navigation - #767

Merged
Medformatik merged 1 commit into
mainfrom
fix/native-navigation-map-rebuild
Nov 4, 2026
Merged

Medformatik merged 1 commit into
mainfrom
fix/native-navigation-map-rebuild

Conversation

@Medformatik

Copy link
Copy Markdown
Collaborator

What changed and why

In the installed app, turn-by-turn navigation showed the whole route as an overview, with no position marker, and the camera never followed. The native session itself was fine: it accepted fixes and sent the page complete progress (snapped position, distance along the route, bearing) every few seconds.

The page rebuilt its map on every one of those updates. useForegroundLocation memoised its callback on the whole mobile runtime context, and that context changes with every native snapshot, because it carries the read model. MapCanvas builds the map in an effect that depends on that callback, so while navigating the map was destroyed and rebuilt every few seconds. Each new map started at the stored overview and asked the shell for a fresh first fix (the bridge showed a location.result after every snapshot.update). The nav camera created its marker and entered follow only when mapReady changed, which a rebuild does not do, so a trip that started during a rebuild never got either. On the device the camera hook's marker ref was null, its follow-entry refs were never written, and a map canvas tagged before a snapshot was gone after it.

  • useForegroundLocation depends only on what decides where a fix comes from: authority, client and runtime state. Snapshots no longer rebuild the map.
  • useNavCamera creates its marker without needing a map (the frame loop attaches it to the current one) and enters follow again when a new map instance appears, but not on a style reload of the same map. The camera now survives any rebuild, such as one after the shell handshake.
  • MobileRuntimeProvider applies bridge snapshots and events when they arrive. It used to apply them to the navigation store inside a setState updater, which React runs while rendering; React warned "Cannot update a component (NavigationRouteLayer) while rendering a different component (MobileRuntimeProvider)" on the device.

Verification

  • On a Pixel (Android 17), the dev app loading this branch's web build against openmapx.com, with a native ground session running: the camera follows with pitch and the heading puck on the route; a map canvas tagged during navigation was still the same element after 6 native snapshots over 60 s; no render-phase warning; a reload resumes the session in follow; End ends it. Before the fix, the same setup showed the overview with no puck. Screenshots are left out because every navigation view shows the streets around my position.
  • New tests: the camera draws its puck and enters follow when navigation starts while the map is being replaced, enters follow again on a replacement map and not on a style reload; the fix callback keeps its identity across snapshots and changes with authority; snapshots reach the store with no render-phase update. Each failed before the fix.
  • Web vitest for lib/mobile, lib/navigation, components/navigation and components/map: 1,603 passed. tsc for apps/web, biome.
  • Not checked: iOS, and a drive on the road.

Release and upgrade impact

Product impact: ordinary

…vigation

In the installed app, turn-by-turn navigation showed the route overview
with no position marker, and the camera never followed.

useForegroundLocation memoised its callback on the whole mobile runtime
context, which changes with every native snapshot. MapCanvas builds the
map in an effect that depends on that callback, so the map was destroyed
and rebuilt every few seconds while navigating, each time at the stored
overview and with a fresh first-fix request. The nav camera created its
marker and entered follow only when mapReady changed, which a rebuild
does not do, so a trip started during a rebuild never got either.

- useForegroundLocation depends only on authority, client and state.
- The nav camera creates its marker without needing a map (the frame
  loop attaches it to the current one) and enters follow again when a
  new map instance appears, but not on a style reload of the same map.
- MobileRuntimeProvider applies bridge snapshots and events when they
  arrive instead of inside a state updater, which React runs while
  rendering and which updated store subscribers mid-render.
@Medformatik
Medformatik enabled auto-merge (squash) November 4, 2026 01:02
@Medformatik
Medformatik merged commit 66dcef7 into main Nov 4, 2026
23 checks passed
@Medformatik
Medformatik deleted the fix/native-navigation-map-rebuild branch November 4, 2026 01:10
@github-actions github-actions Bot locked and limited conversation to collaborators Nov 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant