feat: add global 'beforepopstate' bus to intercept browser back/forward navigation (#509)#511
Conversation
There was a problem hiding this comment.
Pull Request Overview
Adds a global pop-state bus to intercept browser back/forward navigation and exposes a wasPop flag via React context.
- Introduces a centralized pop-state event bus with registration hooks (
usePopStateBus,useOnPopState) - Adds
WasPopProvidercontext to track navigation initiated by browser history - Exposes a high-level
ServicesProviderto wire everything at the app root
Reviewed Changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/services/beforePopState/popStateBus.ts | Core event bus for registering/unregistering pop-state callbacks |
| src/services/beforePopState/types.ts | Type definitions for pop-state callbacks and state |
| src/services/beforePopState/usePopStateBus.ts | Hook to install the global pop-state interceptor |
| src/services/beforePopState/useOnPopState.ts | Hook to register/unregister individual pop-state callbacks |
| src/providers/services/wasPop/context.ts | Creates WasPopContext with default wasPop: false |
| src/providers/services/wasPop/types.ts | Defines WasPopContextProps interface |
| src/providers/services/wasPop/provider.tsx | Implements WasPopProvider to track and reset wasPop |
| src/providers/services/wasPop/hook.ts | useWasPop hook to consume WasPopContext |
| src/providers/services/provider.tsx | ServicesProvider to wire up pop-state bus and WasPopProvider |
Comments suppressed due to low confidence (1)
src/services/beforePopState/useOnPopState.ts:1
- There are no tests covering the registration/unregistration lifecycle in
useOnPopState. Consider adding unit tests to verify that callbacks are registered on mount and removed on unmount.
import { useEffect } from "react";
There was a problem hiding this comment.
Pull Request Overview
This PR adds a global pop‐state event bus and a context‐based system to track browser back/forward navigation, exposing that state to components via hooks and a top‐level services provider.
- Introduces a centralized pop‐state event bus (
popStateBus.ts, types, and hooks) - Adds
WasPopProvider, its context, anduseWasPophook for consuming pop‐navigation state - Adds
ServicesProviderto wire up the pop‐state bus and provider at the application root
Reviewed Changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/services/beforePopState/popStateBus.ts | Implements centralized pop‐state event bus and callback registry |
| src/services/beforePopState/types.ts | Defines types for beforePop callbacks and history state |
| src/services/beforePopState/usePopStateBus.ts | Hook to install the global pop‐state handler |
| src/services/beforePopState/useOnPopState.ts | Hook to register/unregister individual pop‐state callbacks |
| src/providers/services/wasPop/context.ts | Creates WasPopContext with default placeholder values |
| src/providers/services/wasPop/types.ts | Defines WasPopContextProps interface |
| src/providers/services/wasPop/provider.tsx | Implements WasPopProvider to track and expose pop‐state events |
| src/providers/services/wasPop/hook.ts | Provides useWasPop hook to consume pop‐state context |
| src/providers/services/provider.tsx | Adds ServicesProvider that wires up pop‐state bus and provider |
Comments suppressed due to low confidence (2)
src/services/beforePopState/popStateBus.ts:58
- [nitpick] Include more context in this error log (e.g., callback identity or state) to improve debugging when a listener throws.
console.error("Pop listener failed:", e);
src/services/beforePopState/popStateBus.ts:1
- There are no tests covering the pop-state bus behavior; consider adding unit tests for registering, invoking, and unregistering callbacks.
import Router from "next/router";
| beforePopCallbacks.forEach((cb) => { | ||
| try { | ||
| if (cb(state) === false) allAllow = false; | ||
| } catch (e: unknown) { | ||
| console.error("Pop listener failed:", e); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Consider using a for…of loop over the callback set and breaking early when a callback returns false, to avoid invoking all listeners once navigation is already blocked.
| beforePopCallbacks.forEach((cb) => { | |
| try { | |
| if (cb(state) === false) allAllow = false; | |
| } catch (e: unknown) { | |
| console.error("Pop listener failed:", e); | |
| } | |
| }); | |
| for (const cb of beforePopCallbacks) { | |
| try { | |
| if (cb(state) === false) { | |
| allAllow = false; | |
| break; | |
| } | |
| } catch (e: unknown) { | |
| console.error("Pop listener failed:", e); | |
| } | |
| } |
There was a problem hiding this comment.
We might have the case where a "downstream" listeners with an important side-effect never runs... leaving as is!
| @@ -0,0 +1,25 @@ | |||
| import React, { ReactNode } from "react"; | |||
| import { usePopStateBus } from "../../services/beforePopState/usePopStateBus"; | |||
| import { WasPopProvider } from "../services/wasPop/provider"; | |||
There was a problem hiding this comment.
[nitpick] The import path can be simplified to "./wasPop/provider" to avoid the extra directory traversal and improve readability.
| import { WasPopProvider } from "../services/wasPop/provider"; | |
| import { WasPopProvider } from "./wasPop/provider"; |
There was a problem hiding this comment.
Good pick up thank you!
Closes #509.
This pull request introduces a new navigation handling system that tracks browser back/forward navigation events and provides this state to components via context. The changes include creating a centralized pop-state event bus, a context provider for managing navigation state, and hooks for registering callbacks. These updates improve the application's ability to handle user-initiated navigation and provide consistent state management.
Navigation State Management:
src/providers/services/wasPop/context.ts: AddedWasPopContextto provide a context for tracking whether navigation was triggered by a pop-state event.src/providers/services/wasPop/provider.tsx: IntroducedWasPopProviderto manage and expose thewasPopstate, tracking browser navigation events and providing this state to child components.src/providers/services/wasPop/hook.ts: AddeduseWasPophook to allow components to consume thewasPopstate from the context.src/providers/services/wasPop/types.ts: Defined theWasPopContextPropsinterface to specify the shape of thewasPopcontext.Pop-State Event Bus:
src/services/beforePopState/popStateBus.ts: Implemented a centralized pop-state event bus that allows components to register callbacks for handling browser back/forward navigation.src/services/beforePopState/types.ts: Added type definitions forBeforePopStateCallbackandNextHistoryStateto standardize callback signatures and state objects.src/services/beforePopState/useOnPopState.ts: CreateduseOnPopStatehook to register and unregister callbacks with the pop-state bus.src/services/beforePopState/usePopStateBus.ts: AddedusePopStateBushook to initialize the global pop-state handler safely.High-Level Provider:
src/providers/services/provider.tsx: AddedServicesProviderto initialize and provide access to the navigation handling system by combiningusePopStateBusandWasPopProvider. This ensures all components can access the navigation state.