diff --git a/packages/location-state-core/src/provider.tsx b/packages/location-state-core/src/provider.tsx index 9844e74b..7c3d3340 100644 --- a/packages/location-state-core/src/provider.tsx +++ b/packages/location-state-core/src/provider.tsx @@ -1,33 +1,41 @@ import { LocationStateContext } from "./context"; import { StorageStore, Store, URLStore } from "./stores"; import { NavigationSyncer } from "./syncers"; - import { Syncer } from "./types"; import { ReactNode, useEffect, useState } from "react"; +export type Stores = Record; +export type CreateStores = (syncer: Syncer) => Stores; + +export const createDefaultStores: CreateStores = (syncer) => ({ + session: new StorageStore(globalThis.sessionStorage), + url: new URLStore(syncer), +}); + export function LocationStateProvider({ children, ...props }: { syncer?: Syncer; + stores?: Stores | CreateStores; children: ReactNode; }) { const [syncer] = useState( () => props.syncer ?? new NavigationSyncer(window.navigation), ); - const [contextValue] = useState(() => ({ - stores: { - session: new StorageStore(globalThis.sessionStorage), - url: new URLStore(syncer), - }, - })); + // Generated on first render to prevent provider from re-rendering + const [contextValue] = useState(() => { + const stores = props.stores ?? createDefaultStores; + return { + stores: typeof stores === "function" ? stores(syncer) : stores, + }; + }); useEffect(() => { - const stores = contextValue.stores; const abortController = new AbortController(); const { signal } = abortController; const applyAllStore = (callback: (store: Store) => void) => { - Object.values(stores).forEach(callback); + Object.values(contextValue.stores).forEach(callback); }; const key = syncer.key()!;