From 56f83c868fd1b53de10b2db1b35337c4c65e35b8 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Tue, 9 Mar 2021 11:42:28 +0100 Subject: [PATCH 1/7] Use history.replaceState for route function --- packages/preact-iso/router.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/preact-iso/router.js b/packages/preact-iso/router.js index 2766ae276..8a3115ff7 100644 --- a/packages/preact-iso/router.js +++ b/packages/preact-iso/router.js @@ -1,7 +1,11 @@ import { h, createContext, cloneElement } from 'preact'; import { useContext, useMemo, useReducer, useEffect, useLayoutEffect, useRef } from 'preact/hooks'; -const UPDATE = (state, url, push) => { +const UPDATE = (state, url) => { + /** @type {boolean|undefined} - History state update strategy */ + let push = undefined + + // user click (Mouse event) if (url && url.type === 'click') { const link = url.target.closest('a[href]'); if (!link || link.origin != location.origin) return state; @@ -9,8 +13,12 @@ const UPDATE = (state, url, push) => { url.preventDefault(); push = true; url = link.href.replace(location.origin, ''); + // navigation (PopStateEvent) } else if (typeof url !== 'string') { url = location.pathname + location.search; + // manual invocation (useLocation().route) + } else { + push = false } if (push === true) history.pushState(null, '', url); From 43214d3926b49430b6fa8e484f2962ba83ce96cd Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Tue, 9 Mar 2021 12:12:42 +0100 Subject: [PATCH 2/7] Add semicolons --- packages/preact-iso/router.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/preact-iso/router.js b/packages/preact-iso/router.js index 8a3115ff7..8f0a58708 100644 --- a/packages/preact-iso/router.js +++ b/packages/preact-iso/router.js @@ -3,7 +3,7 @@ import { useContext, useMemo, useReducer, useEffect, useLayoutEffect, useRef } f const UPDATE = (state, url) => { /** @type {boolean|undefined} - History state update strategy */ - let push = undefined + let push = undefined; // user click (Mouse event) if (url && url.type === 'click') { @@ -18,7 +18,7 @@ const UPDATE = (state, url) => { url = location.pathname + location.search; // manual invocation (useLocation().route) } else { - push = false + push = false; } if (push === true) history.pushState(null, '', url); From 0faacea2e6f3648e4577285d89161cc0f8be228e Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Tue, 9 Mar 2021 12:37:23 +0100 Subject: [PATCH 3/7] Add option to use object as a path --- packages/preact-iso/router.d.ts | 2 +- packages/preact-iso/router.js | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/preact-iso/router.d.ts b/packages/preact-iso/router.d.ts index d63fedba3..ba2304f32 100644 --- a/packages/preact-iso/router.d.ts +++ b/packages/preact-iso/router.d.ts @@ -8,7 +8,7 @@ interface LocationHook { url: string; path: string; query: Record; - route: (url: string) => void; + route: (url: string | { url: string, replace?: boolean }) => void; }; export const useLocation: () => LocationHook; diff --git a/packages/preact-iso/router.js b/packages/preact-iso/router.js index 8f0a58708..6e25044d3 100644 --- a/packages/preact-iso/router.js +++ b/packages/preact-iso/router.js @@ -1,24 +1,34 @@ import { h, createContext, cloneElement } from 'preact'; import { useContext, useMemo, useReducer, useEffect, useLayoutEffect, useRef } from 'preact/hooks'; +/** + * @param {string} state + * @param {MouseEvent|PopStateEvent|Object|string} url + * @return {string} + */ const UPDATE = (state, url) => { /** @type {boolean|undefined} - History state update strategy */ - let push = undefined; + let push = undefined - // user click (Mouse event) - if (url && url.type === 'click') { + // user click + if (url instanceof MouseEvent) { + // @ts-ignore-next const link = url.target.closest('a[href]'); if (!link || link.origin != location.origin) return state; url.preventDefault(); push = true; url = link.href.replace(location.origin, ''); - // navigation (PopStateEvent) - } else if (typeof url !== 'string') { + // navigation + } else if (url instanceof PopStateEvent) { url = location.pathname + location.search; - // manual invocation (useLocation().route) + // manual invocation: route({ path, replace }) + } else if (typeof url === 'object') { + url = url.path; + push = !url.replace; + // manual invocation: route(path) } else { - push = false; + push = true; } if (push === true) history.pushState(null, '', url); From 25fd059a19c39cd43106ef04acff32144d614418 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Tue, 9 Mar 2021 13:00:09 +0100 Subject: [PATCH 4/7] Change object signature --- packages/preact-iso/router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/preact-iso/router.js b/packages/preact-iso/router.js index 6e25044d3..9fe887f5f 100644 --- a/packages/preact-iso/router.js +++ b/packages/preact-iso/router.js @@ -24,7 +24,7 @@ const UPDATE = (state, url) => { url = location.pathname + location.search; // manual invocation: route({ path, replace }) } else if (typeof url === 'object') { - url = url.path; + url = url.url; push = !url.replace; // manual invocation: route(path) } else { From d772def956b71dbb156ca0b9d66ff7595322d815 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Mon, 15 Mar 2021 11:05:50 +0100 Subject: [PATCH 5/7] Update code as per https://github.com/preactjs/wmr/pull/413#discussion_r593948478 --- packages/preact-iso/router.js | 38 +++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/preact-iso/router.js b/packages/preact-iso/router.js index 6a43fe956..f268adf1b 100644 --- a/packages/preact-iso/router.js +++ b/packages/preact-iso/router.js @@ -3,27 +3,31 @@ import { useContext, useMemo, useReducer, useEffect, useLayoutEffect, useRef } f /** * @param {string} state - * @param {MouseEvent|PopStateEvent|Object|string} url - * @return {string} + * @param {MouseEvent|PopStateEvent|Object|string} update + * @return {string|undefined} */ -const UPDATE = (state, url) => { +const UPDATE = (state, update) => { /** @type {boolean|undefined} - History state update strategy */ - let push = true; - // user click - if (url instanceof MouseEvent) { - // @ts-ignore-next - const link = url.target.closest('a[href]'); + let push, url; + + if (!update || typeof update === 'string') { + // manual invocation: route(url) + url = update; + push = true; + } else if (update.type === 'click') { + // user click + const link = update.target.closest('a[href]'); if (!link || link.origin != location.origin) return state; - url.preventDefault(); - url = link.href.replace(location.origin, ''); - // navigation - } else if (url instanceof PopStateEvent) { - url = location.pathname + location.search; - push = undefined; - // manual invocation: route({ path, replace }) - } else if (typeof url === 'object') { - url = url.url; + update.preventDefault(); + url = link.pathname + link.search + link.hash; + push = true; + } else if (update.type === 'popstate') { + // navigation + url = location.pathname + location.search + location.hash; + } else { + // manual invocation: route({ url, replace }) + url = update.url || update; push = !url.replace; } From 81f18f7e657bd2eedd1de6a1c142d0d11b0aa162 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Mon, 22 Mar 2021 10:06:14 +0100 Subject: [PATCH 6/7] Wrap reducer to allow different signature --- packages/preact-iso/router.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/preact-iso/router.js b/packages/preact-iso/router.js index f268adf1b..7f9f860df 100644 --- a/packages/preact-iso/router.js +++ b/packages/preact-iso/router.js @@ -1,5 +1,5 @@ import { h, createContext, cloneElement } from 'preact'; -import { useContext, useMemo, useReducer, useEffect, useLayoutEffect, useRef } from 'preact/hooks'; +import { useContext, useMemo, useCallback, useReducer, useEffect, useLayoutEffect, useRef } from 'preact/hooks'; /** * @param {string} state @@ -59,7 +59,8 @@ export const exec = (url, route, matches) => { }; export function LocationProvider(props) { - const [url, route] = useReducer(UPDATE, location.pathname + location.search); + const [url, doRoute] = useReducer(UPDATE, location.pathname + location.search); + const route = useCallback((url, replace) => doRoute({ url, replace }), []); const value = useMemo(() => { const u = new URL(url, location.origin); From 3d0d9f47d192fce8f2ce954520f0e60f2318a10c Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Wed, 24 Mar 2021 10:47:53 +0100 Subject: [PATCH 7/7] Add changeset --- .changeset/fast-suns-flow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fast-suns-flow.md diff --git a/.changeset/fast-suns-flow.md b/.changeset/fast-suns-flow.md new file mode 100644 index 000000000..e2dc49064 --- /dev/null +++ b/.changeset/fast-suns-flow.md @@ -0,0 +1,5 @@ +--- +'preact-iso': patch +--- + +Use pushState/ replaceState for useLocation().route method