From 6b2e0a26a6d6f2ebe0510390415104e1801307cb Mon Sep 17 00:00:00 2001 From: Bart Langelaan Date: Wed, 30 Oct 2024 22:13:57 +0100 Subject: [PATCH] style: Use useSyncExternalStore in the React adapter --- packages/nuqs/src/adapters/react.ts | 48 ++++++++++++++++------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/packages/nuqs/src/adapters/react.ts b/packages/nuqs/src/adapters/react.ts index b35818eb..b1796433 100644 --- a/packages/nuqs/src/adapters/react.ts +++ b/packages/nuqs/src/adapters/react.ts @@ -1,10 +1,27 @@ import mitt from 'mitt' -import { useEffect, useState } from 'react' +import { useSyncExternalStore } from 'react' import { renderQueryString } from '../url-encoding' import type { AdapterOptions } from './defs' import { createAdapterProvider } from './internal.context' -const emitter = mitt<{ update: URLSearchParams }>() +const emitter = mitt<{ update: void }>() + +function subscribe(callback: () => void) { + emitter.on('update', callback) + window.addEventListener('popstate', callback) + return () => { + emitter.off('update', callback) + window.removeEventListener('popstate', callback) + } +} + +function getSnapshot() { + return new URLSearchParams(location.search) +} + +function getServerSnapshot() { + return new URLSearchParams() +} function updateUrl(search: URLSearchParams, options: AdapterOptions) { const url = new URL(location.href) @@ -12,29 +29,16 @@ function updateUrl(search: URLSearchParams, options: AdapterOptions) { const method = options.history === 'push' ? history.pushState : history.replaceState method.call(history, history.state, '', url) - emitter.emit('update', search) + emitter.emit('update') } function useNuqsReactAdapter() { - const [searchParams, setSearchParams] = useState(() => { - if (typeof location === 'undefined') { - return new URLSearchParams() - } - return new URLSearchParams(location.search) - }) - useEffect(() => { - // Popstate event is only fired when the user navigates - // via the browser's back/forward buttons. - const onPopState = () => { - setSearchParams(new URLSearchParams(location.search)) - } - emitter.on('update', setSearchParams) - window.addEventListener('popstate', onPopState) - return () => { - emitter.off('update', setSearchParams) - window.removeEventListener('popstate', onPopState) - } - }, []) + const searchParams = useSyncExternalStore( + subscribe, + getSnapshot, + getServerSnapshot + ) + return { searchParams, updateUrl