Comments (17)
@worudso @dpr-dev Hey guys, thanks for the issue.
Been thinking about this a lot and what I had in mind is following:
// useLocation hook may return a third argument, which is basically a hash
// of query params used; this is completely optional and apps that use
// the hook already won't break
const [location, setLocation, queryParams] = useLocation();
// the signature of the useRoute hook stays the same, however it may return query params
// in the params hash along with dynamic segments
const [match, params] = useRoute("/app/users/:id");
// example: /app/users/alex?tab=settings
// -> { id: "alex", tag: "settings" }
In my opinion this can be one of the optimal solutions because:
- Doesn't break the existing API
- The query + route params merging technique is widely used, for example in Rails or Express (I guess).
Anyway, let me know what you think about this design?
from wouter.
I think separating location.pathname
and location.search
tracking is the right approach.
Some components don't need to react on query string changes, while some do.
If the hook useLocation
is going to track both, it will introduce performance regressions.
For now, to track search
(query string changes) you could use:
I like the separation in react-use between:
- useLocation
- useSearchParam
I believe this library should do the same due to performance reasons and ability for a project to import only what's needed for their specific needs.
from wouter.
Any news about this? It would be great to have access to the search map!
from wouter.
Correct me if I'm wrong but it looks like an update in regards to joaopaulobdac's issue above means a component will rerender if the query params change. So I believe you can just use URLSearchParams
and long as you use useRoute
or useLocation
within the component. So you can make your own hooks using the following to wrap around the existing wouter
api.
import { useLocation as useWouterLocation, useRoute as useWouterRoute } from "wouter";
export const useLocation = () => {
const [location, setLocation] = useWouterLocation();
return [location, setLocation, window.location.search];
};
// const [location, setLocation, search] = useLocation();
export const useRoute = (pattern) => {
let [match, params] = useWouterRoute(pattern);
if (match) {
const urlSearchParams = new URLSearchParams(window.location.search);
const queryParams = Object.fromEntries(urlSearchParams.entries());
// params and queryParams can have the same name
// this preferences params in that scenario
params = {
...queryParams,
...params,
};
}
return [match, params];
}
// const [match, params] = useMatch(pattern);
from wouter.
Any solution ?
from wouter.
I think it is better to return a complex location object, as in RR
{
pathname: string,
search: ''
}
const [location, push] = useLocation(); // Now we can get the search and the path from the location
from wouter.
I tried to use the useSearchParam
hook from react-use but it was not reacting when using wouter's Link
to navigate.
const getValue = (param) => new URLSearchParams(window.location.search).get(param)
function useSearchParam(param) {
const [value, setValue] = useState(() => getValue(param))
useEffect(() => {
const onChange = () => setValue(getValue(param))
window.addEventListener('popstate', onChange)
window.addEventListener('pushstate', onChange)
window.addEventListener('replacestate', onChange)
return () => {
window.removeEventListener('popstate', onChange)
window.removeEventListener('pushstate', onChange)
window.removeEventListener('replacestate', onChange)
}
}, [param])
return value
}
This is because the events they are listening to are pushstate
and replacestate
instead of wouter's pushState
and replaceState
. I don't know who is correct here. Following the SO link from the wouter source code, looks like it should be pushstate
and replacestate
. It's also consistent with the popstate
and other window events names.
I'm leaving this here in case someone else also runs into this problem when using react-use with wouter.
from wouter.
@kilianc No, not yet 😞 There is a discussion going on in #102
The problem isn't in implementing this, but providing a good design that will enable us to keep the size low, plus will be generic enough.
from wouter.
Copying and pasting my response from #177:
The correct way to do this would be something like the example shown here: #232
Tbh, not sure why search changing is causing re-rendering by default... that seems misguided. Since there's currently no subscribe
function exported, could easily write our own:
const events = ["popstate", "pushState", "replaceState", "hashchange"];
function subscribe(callback: () => void) {
for (const event of events) {
window.addEventListener(event, callback);
}
return () => {
for (const event of events) {
window.removeEventListener(event, callback);
}
}
}
function getCurrentValueOfMyParam() {
return someFunctionOf(window.location);
}
And now we can simply do...
const myParam = React.useSyncExternalStore(subscribe, getCurrentValueOfMyParam);
No re-rendering if myParam
hasn't changed, even if a million other things in the url have!
(Notice: no mucking with Router
is necessary at all!)
from wouter.
It works for me.
import React from "react";
import ReactDOM from "react-dom/client";
import { Router } from "wouter";
import useBrowserLocation from "wouter/use-location";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<Router
+ hook={(options) => {
+ const { pathname, search } = new URL(location.href);
+
+ const [_, nav] = useBrowserLocation(options);
+
+ return [pathname + search, nav];
+ }}
>
<App />
</Router>
</React.StrictMode>
);
from wouter.
This is my fork
https://github.com/ownerclan/wouter/blob/master/use-search-params.js
And I implemented useSearchParams
for my immediate needs.
I'm not saying we'd better go useSearchParams
. Instead, I'm saying @molefrog 's new useLocation
might be the right choice. I hope my experiences that dealt with search params help you make a better decision.
The current version of my useSearchParams
returns an array of [key, value]
tuples. But for convenience, returning an object with keys of params is best. I had used that version of useSearchParams
at first. It's like react's old state
and setState
which allows partial update of a state. This design had made my code looks better.
But there's a problem that there can be more than two params with the same name at once(This kind of usage actually exists in my project). And URLSearchParams
object allows it. So we need to forget setState-like setSearchParams
when we don't want to give an strong opionion about the usage of search params.
I think we'd hetter leave this problem(manipulating search params in an elegant way) to another utility library(lodash, immer, etc) and a programmer himself, and focus on conservative representation of URLSearchParams
. But URLSearchParams
object really sucks, I recommend to use an array of [key, value]
tuples. We can map
and filter
and do another array operations on it while we can't with URLSearchParams
.
And there's another problem that with useSearch
thing we have multiple ways to update current url. It makes the behavior of setLocation
and setSearchParams
ugly.
setLocation
can update path and search params andsetSearchParams
can only update search params and should preserve path.
So I 100% agree with new useLocation
. But useRoute
has a problem I metioned before. It can't be used with multiple keys with the same name. I agree that new useRoute
can be useful in some case. But adding that feature in the future will not be breaking changes. How about keeping old simple useRoute
behaviour and delaying changes for now?
from wouter.
@worudso Not sure if I understand what you mean by:
there can be more than two params with the same name at once
You mean the search query might contain things like ?options[]=for&options[]=bar
?
from wouter.
@molefrog yes, that's the case. Whether it's recommended or not, it's already supported by native URLSearchParams
.
from wouter.
@molefrog, very nice implementation
from wouter.
@molefrog's implementation looks like what we need now. Looking for a "hash" property also https://www.w3schools.com/jsref/prop_loc_hash.asp
from wouter.
Has this landed?
from wouter.
is it possible to add search dynamically?
https://codesandbox.io/s/wouter-demo-nested-routes-forked-qmg6q?file=/src/index.js
when pressed add query it will add query but remove previous params.
how to test:
Press "Help Center" and navigate to topics. url will shown help/topics
and pressed add query
it will remove /topics not extending the url.
from wouter.
Related Issues (20)
- Router don't work with Preact (10.18.1) HOT 3
- wouter-preact: Params with typescript? HOT 2
- How to add params in a nesting route? HOT 3
- v2.12.1 npm package is out of sync with v2.12.1 tag HOT 1
- v3.0.0-rc.1: When use hash router, Ctrl+click on <Link>, new window is opened with wrong url HOT 3
- Potential `useSearch` bug not triggering updates when used with `urql` HOT 9
- [Bug] Can't match default <Route>Not found</Route> when Router inside Switch HOT 3
- (?) Hash routing with no prefix slash index.html#/example/path/ HOT 3
- useSearch unsafe parameter decoding HOT 3
- v3.0.0-rc.2 decodeUriComponent is called before route match, breaking links with urlencoded slash (%2F) HOT 2
- v3.0.0-rc.1: `useRoute` should allow `nest` option just like `<Route />` HOT 1
- Suggestion: `<Link>` should always render an `<a>` (or at least have the option to do so) HOT 5
- Accessing nested params with `useParams` HOT 8
- Nested routing broken by intermediate component HOT 2
- Exit animation with framer-motion HOT 7
- How to use V3 with Jest? HOT 3
- [BUG] `useHashLocation` not syncing with state HOT 3
- Docs don't say how to install; no readme on NPM page HOT 1
- import/no-unresolved eslint error being raised on Wouter 3.0.x HOT 3
- Intercept location change with custom hook swallows state HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from wouter.