import { useEffect, useEffectEvent } from "react"; import { urlWithParams } from "./urlState"; // Mirror a set of nav params onto the CURRENT history entry (replaceState — mirroring is not a new // entry) whenever they change. Each provider owns its own key(s) and passes the delta it wants; a null // value clears that key, and urlWithParams preserves every other param (so providers don't clobber each // other). Extracted from the identical replaceState/urlWithParams blocks FeedFiltersProvider and // PlaylistsProvider used to hand-roll, so the mirroring contract lives in one place. export function useUrlMirror(updates: Record): void { // The caller typically passes an inline object literal (new identity every render); key on its // serialized value so the effect only fires when a param actually changes, not every render. const dep = JSON.stringify(updates); // The object itself is read through an effect event, so the effect's one reactive input is the // serialized value — which is exactly what the dep list says: an effect event for the identity that // churns, a primitive for the trigger. const mirror = useEffectEvent(() => { window.history.replaceState(window.history.state, "", urlWithParams(updates)); }); useEffect(() => { mirror(); }, [dep]); }