From cff5024333b5d96615c3e6f977185d1b3097274a Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Fri, 27 Oct 2023 14:14:23 -0600 Subject: [PATCH] fix: history subscription on creation --- .../react/react-search-state/src/main.tsx | 4 +- packages/history/src/index.ts | 99 +++++++++---------- .../react-search-state/src/useSearchState.tsx | 2 +- 3 files changed, 48 insertions(+), 57 deletions(-) diff --git a/examples/react/react-search-state/src/main.tsx b/examples/react/react-search-state/src/main.tsx index e435d5fe26..63a4863302 100644 --- a/examples/react/react-search-state/src/main.tsx +++ b/examples/react/react-search-state/src/main.tsx @@ -43,7 +43,7 @@ function App() { const projectState = useSearchState({ key: 'project', useDefaultValue: () => 'Nozzle', - // writeDefault: true, + writeDefault: true, // defaultReplace: true, }) @@ -51,7 +51,7 @@ function App() { key: 'mode', useDeps: () => [projectState.state], useDefaultValue: useLocalDefaultValue(() => 'users'), - // writeDefault: true, + writeDefault: true, usePersister: localPersister, defaultReplace: true, }) diff --git a/packages/history/src/index.ts b/packages/history/src/index.ts index 5e60e476f8..b6f73dbf83 100644 --- a/packages/history/src/index.ts +++ b/packages/history/src/index.ts @@ -13,6 +13,8 @@ export interface RouterHistory { createHref: (href: string) => string block: (blockerFn: BlockerFn) => () => void flush: () => void + destroy: () => void + update: () => void } export interface HistoryLocation extends ParsedPath { @@ -50,7 +52,6 @@ const stopBlocking = () => { function createHistory(opts: { getLocation: () => HistoryLocation - subscriber: false | ((onUpdate: () => void) => () => void) pushState: (path: string, state: any, onUpdate: () => void) => void replaceState: (path: string, state: any, onUpdate: () => void) => void go: (n: number) => void @@ -58,16 +59,21 @@ function createHistory(opts: { forward: () => void createHref: (path: string) => string flush?: () => void + destroy?: () => void }): RouterHistory { let location = opts.getLocation() - let unsub = () => {} let subscribers = new Set<() => void>() let blockers: BlockerFn[] = [] let queue: (() => void)[] = [] - const tryFlush = () => { + const onUpdate = () => { + location = opts.getLocation() + subscribers.forEach((subscriber) => subscriber()) + } + + const tryUnblock = () => { if (blockers.length) { - blockers[0]?.(tryFlush, () => { + blockers[0]?.(tryUnblock, () => { blockers = [] stopBlocking() }) @@ -78,19 +84,12 @@ function createHistory(opts: { queue.shift()?.() } - if (!opts.subscriber) { - onUpdate() - } + onUpdate() } const queueTask = (task: () => void) => { queue.push(task) - tryFlush() - } - - const onUpdate = () => { - location = opts.getLocation() - subscribers.forEach((subscriber) => subscriber()) + tryUnblock() } return { @@ -98,19 +97,10 @@ function createHistory(opts: { return location }, subscribe: (cb: () => void) => { - if (subscribers.size === 0) { - unsub = - typeof opts.subscriber === 'function' - ? opts.subscriber(onUpdate) - : () => {} - } subscribers.add(cb) return () => { subscribers.delete(cb) - if (subscribers.size === 0) { - unsub() - } } }, push: (path: string, state: any) => { @@ -159,6 +149,8 @@ function createHistory(opts: { } }, flush: () => opts.flush?.(), + destroy: () => opts.destroy?.(), + update: onUpdate, } } @@ -273,38 +265,8 @@ export function createBrowserHistory(opts?: { } } - return createHistory({ + const history = createHistory({ getLocation, - subscriber: (onUpdate) => { - window.addEventListener(pushStateEvent, () => { - currentLocation = parseLocation(getHref(), window.history.state) - onUpdate() - }) - window.addEventListener(popStateEvent, () => { - currentLocation = parseLocation(getHref(), window.history.state) - onUpdate() - }) - - var pushState = window.history.pushState - window.history.pushState = function () { - let res = pushState.apply(history, arguments as any) - if (tracking) onUpdate() - return res - } - var replaceState = window.history.replaceState - window.history.replaceState = function () { - let res = replaceState.apply(history, arguments as any) - if (tracking) onUpdate() - return res - } - - return () => { - window.history.pushState = pushState - window.history.replaceState = replaceState - window.removeEventListener(pushStateEvent, onUpdate) - window.removeEventListener(popStateEvent, onUpdate) - } - }, pushState: (path, state, onUpdate) => queueHistoryAction('push', path, state, onUpdate), replaceState: (path, state, onUpdate) => @@ -314,7 +276,37 @@ export function createBrowserHistory(opts?: { go: (n) => window.history.go(n), createHref: (path) => createHref(path), flush, + destroy: () => { + window.history.pushState = pushState + window.history.replaceState = replaceState + window.removeEventListener(pushStateEvent, history.update) + window.removeEventListener(popStateEvent, history.update) + }, + }) + + window.addEventListener(pushStateEvent, () => { + currentLocation = parseLocation(getHref(), window.history.state) + history.update + }) + window.addEventListener(popStateEvent, () => { + currentLocation = parseLocation(getHref(), window.history.state) + history.update }) + + var pushState = window.history.pushState + window.history.pushState = function () { + let res = pushState.apply(window.history, arguments as any) + if (tracking) history.update() + return res + } + var replaceState = window.history.replaceState + window.history.replaceState = function () { + let res = replaceState.apply(window.history, arguments as any) + if (tracking) history.update() + return res + } + + return history } export function createHashHistory(): RouterHistory { @@ -342,7 +334,6 @@ export function createMemoryHistory( return createHistory({ getLocation, - subscriber: false, pushState: (path, state) => { currentState = state entries.push(path) diff --git a/packages/react-search-state/src/useSearchState.tsx b/packages/react-search-state/src/useSearchState.tsx index f7eb0933b6..e27fcab6a4 100644 --- a/packages/react-search-state/src/useSearchState.tsx +++ b/packages/react-search-state/src/useSearchState.tsx @@ -182,7 +182,7 @@ export function useSearchState< ...prev, [key]: functionalUpdate(updater, prev[key]), }), - replace: opts?.replace ?? defaultReplace, + replace: opts?.replace ?? defaultReplace ?? true, state: opts?.state, })