Skip to content

Commit

Permalink
perf: use next.js router if available
Browse files Browse the repository at this point in the history
  • Loading branch information
wanjas committed May 2, 2024
1 parent d5af17b commit ff9d6a7
Showing 1 changed file with 24 additions and 8 deletions.
32 changes: 24 additions & 8 deletions packages/core/src/router.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
export type Callback = (newSearchParams: string) => void;

declare global {
interface Window {
next?: {
router?: {
push: (href: string) => void;
};
};
}
}

export interface UrlStateRouter {
push(href: string): void;

Expand All @@ -11,52 +21,58 @@ export type GenericRouterOptions = {
poolingIntervalMs?: number;
};

const subscribers = new Map<Callback, Callback>();

let genericRouterCurrentStateString = '';
export class GenericRouter implements UrlStateRouter {
private interval: number = 0;
private subscribers = new Map<Callback, Callback>();

constructor(private options: GenericRouterOptions) {
this.options = { poolingIntervalMs: 100, ...options };
}

push(href: string): void {
window.history.pushState({}, '', href);
// Use Next.js router if available
// Next.js exposes a global object `window.next.router` with a `push` method for both /pages and /app routes
if (typeof window.next?.router?.push === 'function') {
window.next.router.push(href);
} else {
window.history.pushState({}, '', href);
}
this.onSearchParamsChange();
}

subscribe(fn: Callback): void {
subscribers.set(fn, fn);
this.subscribers.set(fn, fn);

if (!this.interval) {
this.startPolling();
}
}

unsubscribe(fn: Callback): void {
subscribers.delete(fn);
this.subscribers.delete(fn);

if (subscribers.size === 0) {
if (this.subscribers.size === 0) {
this.stopPolling();
}
}

onSearchParamsChange(): void {
if (window.location.search !== genericRouterCurrentStateString) {
genericRouterCurrentStateString = window.location.search;
subscribers.forEach((subscriber) =>
this.subscribers.forEach((subscriber) =>
subscriber(genericRouterCurrentStateString),
);
}
}

private startPolling(): void {
// 'popstate' event in browser is not reliable, so we need to poll
// https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event#when_popstate_is_sent
if (typeof window !== 'undefined') {
this.interval = setInterval(() => {
this.onSearchParamsChange();
}, this.options.poolingIntervalMs) as unknown as number; // fix for NodeJS
}, this.options.poolingIntervalMs) as unknown as number; // type fix for NodeJS
}
}

Expand Down

0 comments on commit ff9d6a7

Please sign in to comment.