- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 107
 
(preact-iso): Use pushState/ replaceState for useLocation().route method #413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
(preact-iso): Use pushState/ replaceState for useLocation().route method #413
Conversation
          🦋 Changeset detectedLatest commit: 3d0d9f4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
 Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR  | 
    
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this was already supported?
route('/url', true)
(admittedly, push=true might be a better default)
| path: string; | ||
| query: Record<string, string>; | ||
| route: (url: string) => void; | ||
| route: (url: string | { url: string, replace?: boolean }) => void; | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if we can use (url, replace) here? That would match preact-router.
| 
           @developit wmr/packages/preact-iso/router.js Lines 44 to 51 in 58f1bff 
 Probably we would have to refactor router code to not use reducer in this case (which may be not a bad idea to handle history outside/ without reducer).  | 
    
| 
           I prefer   | 
    
| 
           I've created new PR in #424 to fix the bug with location change after using  After it's resolved it will be easier to move forward with adding an option such as   | 
    
| 
           Nice - thanks for pulling that out, just merged it.  | 
    
        
          
                packages/preact-iso/router.js
              
                Outdated
          
        
      | } else if (url instanceof PopStateEvent) { | ||
| url = location.pathname + location.search; | ||
| // manual invocation: route({ path, replace }) | ||
| } else if (typeof url === 'object') { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's what I'd suggest, in order to preserve the duck typing (as mentioned in previous comment):
const UPDATE = (state, update) => {
	/** @type {boolean|undefined} - History state update strategy */
	let push, url;
	if (!update || typeof update === 'string') {
		url = update;
		push = true;
	}
	else if (update.type === 'click') {
		// user click
		// @ts-ignore-next
		const link = update.target.closest('a[href]');
		if (!link || link.origin != location.origin) return state;
		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) or route({ url, replace })
		url = update.url || update;
		push = !url.replace;
	}
	if (push === true) history.pushState(null, '', url);
	else if (push === false) history.replaceState(null, '', url);
	return url;
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we allow passing a value that evaluates to false (undefined/ null) with route method?
If so, then should it be added to history?
	if (!update || typeof update === 'string') {
	//  ^When the update is not either string or event I'd say it must be an object?
	else {
		// manual invocation: route(url) or route({ url, replace })
		url = update.url || update;
		//                  ^There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated PR with code you suggested, adapting to eslint/ prettier rules
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@developit
What do you think about my comments above?
# Conflicts: # packages/preact-iso/router.js
| 
           I've updated PR to use code suggested in #413 (comment) However I'm not happy with the   | 
    
| 
           @piotr-cz I think we might be able to create a wrapper function in the provider that swaps the argument signature: -	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 }), []);It might even be possible to simplify the history event handling this way too.  | 
    
| 
           @developit  | 
    
| 
           Just one question:  | 
    
| 
           I'd go for patch yea  | 
    
At this moment when using
useLocation().route('/foobar')window location doesn't change: neitherhistory.pushStatenorhistory.replaceStatemethod is used.This pull request
pushState.replaceStateOriginally the useReducer hook dispatcher had a third
pushargument, but dispatchers consume only two arguments.wmr/packages/preact-iso/router.js
Line 4 in 58f1bff
I'm not sure if I should bump patch or minor version with changeset?