diff --git a/.gitignore b/.gitignore
index f4f072f2..f0dbfb17 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@ package-lock.json
nextjs.d.ts
historyjs.d.ts
+static.d.ts
diff --git a/esm-postbuild.sh b/esm-postbuild.sh
index 4cbd4f1c..c4fa859a 100755
--- a/esm-postbuild.sh
+++ b/esm-postbuild.sh
@@ -6,3 +6,4 @@ cat >build/cjs/package.json <', () => {
+ const { useQuery } = factoryParameters(
+ {
+ someParameter: pm('parameter', serializers.string),
+ },
+ { someParameter: 'test' }
+ )
+ const ComponentThatRendersSomethingStatically = () => {
+ const {
+ pushState,
+ replaceState,
+ values: { someParameter },
+ } = useQuery()
+ return (
+ <>
+ {someParameter}
+
+
+
+ >
+ )
+ }
+
+ it('should render a static search string', () => {
+ render(
+
+
+
+ )
+ expect(screen.getByRole('content').textContent).toEqual('myValue')
+ })
+
+ it('should support replace and push state', async () => {
+ render(
+
+
+
+ )
+ await act(async () => {
+ await userEvent.click(screen.getByRole('push'))
+ })
+ expect(screen.getByRole('content').textContent).toEqual('nextPushState')
+ await act(async () => {
+ await userEvent.click(screen.getByRole('replace'))
+ })
+ expect(screen.getByRole('content').textContent).toEqual('nextReplaceState')
+ })
+})
diff --git a/src/lib/adapters/nextjs/index.tsx b/src/lib/adapters/nextjs/index.tsx
index fdc43fa1..0723ed2f 100644
--- a/src/lib/adapters/nextjs/index.tsx
+++ b/src/lib/adapters/nextjs/index.tsx
@@ -19,7 +19,6 @@ import { shallow } from 'zustand/shallow'
import { StoreState } from '../../middleware.js'
import { HistoryManagement, StoreContext, useGeschichte } from '../../store.js'
import type { UrlObject } from 'url'
-import type { ParsedUrlQuery } from 'querystring'
const split = (url?: string) => url?.split('?') || []
@@ -37,10 +36,6 @@ interface Props {
readonly defaultPushOptions?: TransitionOptions
readonly defaultReplaceOptions?: TransitionOptions
// tslint:disable-next-line:no-mixed-interface
- readonly routerAsPath?: () => string
- readonly routerQuery?: () => ParsedUrlQuery
- readonly clientSideHref: () => string
- readonly clientSideSearch: () => string
readonly routerPush?: (
url: Url,
as: UrlObject,
@@ -57,9 +52,6 @@ interface Props {
// FIXME: Somehow imports are messed up for nextjs when importing from modules (see https://github.com/vercel/next.js/issues/36794)
const Router = (NextRouter as any as { readonly default: Router$ }).default
-const defaultClientSideHref = () => window.location.href
-const defaultClientSideSearch = () => window.location.search
-
const queryFromPath = (path: string) => {
const [, query] = split(path)
return `?${query || ''}`
@@ -71,30 +63,21 @@ export const GeschichteForNextjs: FC = ({
initialClientOnlyAsPath,
defaultPushOptions,
defaultReplaceOptions,
- routerAsPath,
- routerQuery,
routerPush,
routerReplace,
- clientSideHref,
- clientSideSearch,
}) => {
const lastClientSideQuery = useRef(initialClientOnlyAsPath)
-
const historyInstance: HistoryManagement = useMemo(() => {
- const thisRouterAsPath = () =>
- routerAsPath ? routerAsPath() : Router.asPath
- const thisRouterQuery = () => (routerQuery ? routerQuery() : Router.query)
-
return {
initialSearch: () => {
const [, query] =
typeof window === 'undefined'
? split(asPath)
- : split(lastClientSideQuery.current || thisRouterAsPath())
+ : split(lastClientSideQuery.current || Router.asPath)
return `?${query || ''}`
},
push: (query, options) => {
- const [pathname] = split(thisRouterAsPath())
+ const [pathname] = split(Router.asPath)
const routerOptions = {
...defaultPushOptions,
...options,
@@ -102,19 +85,19 @@ export const GeschichteForNextjs: FC = ({
if (routerPush) {
return routerPush(
- { pathname, query: thisRouterQuery() },
+ { pathname, query: Router.query },
{ pathname, query },
routerOptions
)
}
return Router.push(
- { pathname, query: thisRouterQuery() },
+ { pathname, query: Router.query },
{ pathname, query },
routerOptions
)
},
replace: (query, options) => {
- const [pathname] = split(thisRouterAsPath())
+ const [pathname] = split(Router.asPath)
const routerOptions = {
...defaultReplaceOptions,
@@ -123,20 +106,20 @@ export const GeschichteForNextjs: FC = ({
if (routerReplace) {
return routerReplace(
- { pathname, query: thisRouterQuery() },
+ { pathname, query: Router.query },
{ pathname, query },
routerOptions
)
}
return Router.replace(
- { pathname, query: thisRouterQuery() },
+ { pathname, query: Router.query },
{ pathname, query },
routerOptions
)
},
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [routerPush, routerReplace, routerQuery, routerAsPath])
+ }, [routerPush, routerReplace])
const useStore = useMemo(
() => useGeschichte(historyInstance),
@@ -155,8 +138,8 @@ export const GeschichteForNextjs: FC = ({
useEffect(() => {
// tslint:disable-next-line
- lastClientSideQuery.current = clientSideHref()
- updateFromQuery(clientSideSearch())
+ lastClientSideQuery.current = window.location.href
+ updateFromQuery(window.location.search)
// tslint:disable-next-line:no-let
let skipEvent = true
const routeChangeStartHandler = (path: string) => {
@@ -173,7 +156,7 @@ export const GeschichteForNextjs: FC = ({
return () => {
Router.events.off('beforeHistoryChange', routeChangeStartHandler)
}
- }, [updateFromQuery, clientSideHref, clientSideSearch])
+ }, [updateFromQuery])
useEffect(() => {
const { unregister } = state
@@ -192,12 +175,10 @@ type ClientOnlyProps = Pick<
| 'defaultReplaceOptions'
| 'routerPush'
| 'routerReplace'
- | 'routerAsPath'
- | 'routerQuery'
> & {
readonly children: ReactNode
readonly omitQueries?: boolean
-} & Partial>
+}
// see https://nextjs.org/docs/api-reference/next/router#routerpush for options;
// in general we want shallow (see https://nextjs.org/docs/routing/shallow-routing) routing in most cases and not scroll
@@ -207,8 +188,6 @@ export const GeschichteForNextjsWrapper: FC = ({
omitQueries = true,
defaultPushOptions = defaultRoutingOptions,
defaultReplaceOptions = defaultRoutingOptions,
- clientSideSearch = defaultClientSideSearch,
- clientSideHref = defaultClientSideHref,
...props
}) => {
const { asPath } = useRouter()
@@ -235,8 +214,6 @@ export const GeschichteForNextjsWrapper: FC = ({
initialClientOnlyAsPath={thisAsPath}
defaultReplaceOptions={defaultReplaceOptions}
defaultPushOptions={defaultPushOptions}
- clientSideHref={clientSideHref}
- clientSideSearch={clientSideSearch}
asPath={pp}
{...props}
/>
diff --git a/src/lib/adapters/static/index.tsx b/src/lib/adapters/static/index.tsx
new file mode 100644
index 00000000..fe9ffa11
--- /dev/null
+++ b/src/lib/adapters/static/index.tsx
@@ -0,0 +1,28 @@
+import React, { memo, useMemo } from 'react'
+import { HistoryManagement, StoreContext, useGeschichte } from '../../store.js'
+
+interface Props {
+ readonly search?: string
+}
+
+const StaticGeschichteProvider = ({
+ search,
+ children,
+}: React.PropsWithChildren) => {
+ const historyInstance: HistoryManagement = useMemo(() => {
+ return {
+ initialSearch: () => search || '?',
+ push: async () => {
+ return
+ },
+ replace: async () => {
+ return
+ },
+ }
+ }, [search])
+
+ const value = useMemo(() => useGeschichte(historyInstance), [historyInstance])
+ return {children}
+}
+
+export default memo(StaticGeschichteProvider)