molefrog / wouter Goto Github PK
View Code? Open in Web Editor NEWπ₯’ A minimalist-friendly ~2.1KB routing for React and Preact
Home Page: https://npm.im/wouter
License: The Unlicense
π₯’ A minimalist-friendly ~2.1KB routing for React and Preact
Home Page: https://npm.im/wouter
License: The Unlicense
Hello,
Is there any way to use the component to open a new tab at that location?
Thanks
My recommendation is to add coverage badge, example codecov
.
Routes only work with <Link>
but when you go directly to a route it just throws 404. What's about adding support for direct requests like in React Router?
I'm getting Uncaught RangeError: Maximum call stack size exceeded
while using useLocation
right from 'wouter' package
import { useLocation } from 'wouter';
this works fine
import useLocation from 'wouter/use-location';
Hey @StrayFromThePath @StrayFromThePath I'm super excited to have types finally in the project! I managed to spent some time reading the sources and although I'm not a TS user I've got some feedback I thought I need to share with you.
Params
typeThe current Params
type is a union of hash or null
. This works fine for the Match
type which can represent either [true, { ... }]
or [false, null]
, however this also assumes that the render prop can contain the null as a first argument here. I think we can narrow the type even further, because the render prop always guarantees that the argument is a valid object.
So how can this be solved? I suggest we make the Params type to always be an object and mark that the match result could contain null:
type Params = { [paramName: string]: string }
// it this a real TypeScript code? :) I'm not sure, but you get the idea
type Match = [boolean, Params | null];
// or is this even possible:
type Match = [true, Params] | [false, null];
match
props from Route
This prop is an internal thing used by the switch, so it's not part of the public API. I suggest we either remove it or change the type, since it's not a boolean anymore, but Match
. But I think it's easier to just remove this.
children
in Router
As @StrayFromThePath pointed out in #54, some components need proper types to support mixed React nodes. The current type of the children
prop in Router
is ReactElement | ReactElement[];
, but this makes it impossible to use something like:
<Router>
Hello, this is an <Application />
We also have <Footer /> and some {1337} numbers here.
</Router>
Same applies to Link
. Generally speaking, anything that React.Provider
accepts should work here as well.
Let me know what you guys think and keep up with the good work!
I see the published package contains import
statements. This produce the following error in default create react app setup after running npm test
Test suite failed to run
/home/igor/react-hooks-beer-example/node_modules/wouter/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import locationHook from "./use-location.js";
^^^^^^^^^^^^
SyntaxError: Unexpected identifier
Can we publish a transpiled version containing require
statements so no babel transpilation would be required inside node_modules
?
This will allow to use proper types.
As @ai pointed out on Twitter, things from './history'
won't work in native ES modules. Need to simulate this and make sure everything is written according to the spec.
I just saw the Redirect
component exported in the source code, but I couldn't find it documented anywhere, this is just a heads up but if I find time over the weekend I'll try to document it myself π
Would it be possible to support the following using the browser's history.state
API, optionally allowing history[method](stateObj, 0, to)
, instead of always using history.[method](0, 0, to)
?
e..g.
<Link href="/" state={{ exampleState: true }}>Link</Link>
and
const [location, setLocation] = useLocation();
setLocation("/", { exampleState: true });
Not sure where the accessor makes the most sense, maybe something like:
import { useRouterState } from 'wouter';
const routerState = useRouterState();
Thanks!
Here's an idea:
Cast parameters as integers when it can, leave it otherwise.
Use case: I'm comparing match.id
with object.id
to apply a selected
class and it would be great to not have to use ==
and not have to cast it myself.
Why: I don't see casting parameter types inside the scope of my application, but rather belonging to the routing mechanism.
How would I do: test each parameter value for a string of numbers and apply parseInt
accordingly.
I can hack it together and send a PR if you like it. Also, let me know if think another approach would be best.
Cheers! πΊ
Missing description about Router component
Since the library was created to be as small as possible it would make sense to add support for Preact. It should only support the version 10 of Preact, which isn't fully released yet, but supports hooks and fragments.
There are few interested problems that we will need to solve in order to release this. Here is how I see the final API:
// regular imports
import { Route, Switch, Link } from "wouter/preact";
// additional modules
import staticHistory from "wouter/preact/extra/static-history.js"
We can do that by simply creating a new folder preact
in the repo with one file called react-deps.js
with all react/preact exports such as useState
, createElement
and so on. The folder can be prepopulated with the sources from the root folder on prepublish
npm script (might need to use this package https://www.npmjs.com/package/copyfiles for cross-platfom support). We shouldn't commit anything except for preact/react-deps.js
however, the files should be gitginored!
The implementation plan:
isValidElement
and Children.map
. Merge #27 and check that it doesn't break anything./preact/react-deps.js
and /react-deps.js
and write a prepublish script.Route
, Link
and Switch
work. A 2-3 test cases should be enough. One thing that isn't clear yet is how to require right react-deps.js
in tests without having sources in preact
folder. Maybe Jest mocks?Hello, I'm trying to implement basepath into my application. I followed the README's instruction. Everything works well, except <Link />
component.
For example,
<Link href="/path">link</Link>
It's fine that clicking on it will navigate to :basepath/path
, but the href prop is still /path
.
Now I had to use <Link />
in this way,
<Link href="/path">
<span><a href={`${basepath}/path`}>link</a></span>
</Link>
Any idea on it?
Hello,
After 4 years of using React, I finally see a reasonable react-router.
There's just one thing I'd appreciate.
Could you please provide typescript type definitions? Either include it in this package, or add them to definitely-typed repo.
Thank you!
Wouter can't be used with TypeScript and Preact at the same time.
If you install @types/wouter
, that also installs @types/react
, which conflicts with and breaks type definitions for preact.
It (probably) works if you use preact-compat
, but at that point you're not really "compatible with preact" in my opinion.
A possible fix would be to push an alternative @types/wouter-preact
that worked with Preact's type definitions.
CC @StrayFromThePath - Thought this would be relevant for you.
Is there a way to have a default route?
In the latest version of wouter, when the location is somewebsite.com/users?name=john
const [location] = useLocation();
location
only retrieves /users
emitting ?name=john
. And even though I push new query params with other methods, re-rendering is not triggered. But sometimes a view needs to depend on search params.
I think we have two options in a broad sense
add useSearch
thing
const [search, setSearch] = useSearch();
search // "?name=john"
or we can let wouter give searchParams
as a URLSearchParams
object, the parsed one.
or how about useURL
which gives current location as URL object?
let location
be location.pathname + location.search
.
breaking change!
In this case, we got a new problem to redefine routing rules. Should useRoute
provide matching for search parameters? I don't think so. Routing rules can go the same just ignoring search.
And the parsing for location.pathname + location.search
is annoying. AFAIK, there is no builtin function to parse it. And even if there is, the code to parse would be repeated in many components.
Hello! :)
I've just added wouter-preact to my preact + typescript boilerplate. I'm using ts-jest for tests with ts-jest preset. Unfortunately I cannot test app.tsx component which contains
import { Link, Route } from 'wouter-preact';
After running yarn test
I've got:
FAIL src/app/app.spec.tsx
β Test suite failed to run/home/mk/Documents/repos/preact-ts-parcel/node_modules/wouter-preact/index.js:1 ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import locationHook from "./use-location.js"; ^^^^^^^^^^^^ SyntaxError: Unexpected identifier 1 | import { h } from 'preact'; > 2 | import { Link, Route } from 'wouter-preact'; | ^ 3 | import { TypedComponent } from '../shared/typings/prop-types'; 4 | import { actions, StoreState } from '../store'; 5 | import { useAction, useSelector } from '@preact-hooks/unistore'; at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:537:17) at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:579:25)
I'm not saying that this is a problem with wouter-preact itself, because it may be e.g. ts-jest problem or maybe even I did something wrong in terms of configuration (see below) but could you add also commonjs output?
jest.config.js
module.exports = {
preset: 'ts-jest',
roots: ['<rootDir>/src'],
verbose: true,
transform: {
'^.+\\.(t|j)sx?$': 'ts-jest',
},
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
};
tsconfig.json:
{
"compilerOptions": {
"outDir": "./dist",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"target": "es6",
"jsx": "react",
"jsxFactory": "h",
"allowJs": true
},
"include": ["./src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts", "**/*.spec.tsx"]
}
I've been trying with different tsconfig.json configurations (also without "include" & || "exclude" fields) but without success.
Related issue (?): #70
Nested Switch does not render nested in Route => Switch
I mean Switch => Route => (Switch) => (Route) <- not renders
You can see everything in this sandbox:
CodeSandbox
Since basepath
has been merged , we need to add types.
If we will try to use path-to-regexp
package it will break the router just because it uses another semantics. I have written a custom makeMatcher
function to make it possible to use it. It is not perfect but at least doesn't break the system.
The getRegexp(pattern);
function doesn't return tuple but just regex in the path-to-regexp
package
Also, this workaround allows creating i18n routes like /:lang(en|es|pt)/posts/:id
.
function makeMatcher(makeRegexpFn = pathToRegexp) {
const cache: { [key: string]: RegExp } = {};
// obtains a cached regexp version of the pattern
const getRegexp = (pattern: string) =>
(cache[pattern]) || (cache[pattern] = makeRegexpFn(pattern));
return (pattern: Path, path: Path) => {
const regexp = getRegexp(pattern);
const found = pattern.match(/:(\w+)/ig);
const keys = found ? found.map(el => el.substr(1)) : [];
const out = regexp.exec(path);
if (!out) return [false, null];
// formats an object with matched params
const params = keys.reduce((params, key, i) => {
params[key] = out[i + 1];
return params;
}, {});
return [true, params];
};
}
...
<Router matcher={makeMatcher(pathToRegexp)}>
Hello,
Been having some issues with params values in the sense that with long text params the space symbols still stays in the props value extracted and i have to use decodeURIComponent.
Is there anyway props value could be formatted by default?
I've just merged the new version 2.0.0 into the master branch and published a 2.0.0-alpha
on npm. Now the types have to be updated. The API is pretty much the same, except that the history
object is replaced with useLocation
hook. See README.md for more details.
i wrote a demo:
<Switch>
<Route path="/:anything*">Default Route: nothing found!</Route>
<Route path="/users/one">Users One</Route>
<Route path="/">First Route</Route>
//...
{/* <Route path="/:anything*">Default Route: nothing found!</Route> */}
</Switch>
If we accidentally put the default route in front, it will cause problems.
I think there are two ways:
<Route default component={AnyComponent}/>
and the position is irrelevant, is it a good idea?wouter v1.3.1 & v1.3.2 can't resolve the react-depts
dependency.
Module not found: Error: Can't resolve './react-deps.js' in '/Users/timo/Code/rg/node_modules/wouter'
This looks neat!
Does it support relative links and routes like Reach Router?
How to implement correctly, return to the previous router without a server?
This code will throw an error:
<Switch>
Hello, <b>world!</b>
</Switch>
Hi @molefrog, nice plugin, i love the Hooks approace!
I have discovered that the Link component didn't accept a onClick prop to do something other then the normal behavior of navigate.
I have implemented the code to support this functionality locally, can i make a PR to merge with your package?
Thanks in advance!
Instead of anonymous function, returns a useCallback https://github.com/molefrog/wouter/blob/master/use-location.js#L16
const [, setLocation] = useLocation()
setLocation should be the same on each render
Hello
Expected Behavior
When switching to root: / there are subpages that I need to display with Layout (Header, Footer, etc.)
Current behavior
https://codesandbox.io/s/nameless-cdn-z1tzs
When switching to /images get 404, but must images component with layout
For desktop browsers there are typical navigation patterns to open the link in a new tab instead of the current one. The most common one is ctrl + click
or clicking with the middle mouse button. Currently this doesn't work because the event will always be prevented:
Lines 91 to 98 in c9c7900
In preact-router
we have this line which explicitly checks for common key combinations and lets the browser handle the event instead:
// ignore events the browser takes care of already:
if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.button!==0) return;
Has anyone used this library with React Native?
Any interesting experiences to share?
I'm checking if a param was provided, otherwise I redirect to login page, but it's not working when the setLocation
is inside a useState
, I tried within a useEffect
and setTimeout
and it works properly.
Hi!
great work!
i have just added support for wouter into https://github.com/salvoravida/redux-first-history.
Demo here: https://codesandbox.io/s/wy5qw1125l
Hello again ππ»
I'm made demo on gh-pages and I can't specify base path for router (in my case it wouter-async-routes
)
need this feature ππ»ββοΈ
If, for example, we use redux-sagas, and we'd like to navigate from a saga, what's the supposed way to connect wouter?
useRouter
and do redirectsI made a <Switch>
component like this:
import { useRouter } from 'wouter'
const Switch = ({ children }) => {
const router = useRouter()
const path = router.history.path()
const childPaths = children.map(c => c.props.path)
let matchedIndex
childPaths.forEach((childPath, idx) => {
const match = router.matcher(childPath, path)[0]
if (isNaN(matchedIndex) && match) {
matchedIndex = idx
}
})
return children[matchedIndex]
}
export default Switch
This just checks which of the children's path matches first and renders that Route. This sorta works, but when I navigate using router.history.push()
afterwards, I get blank screens and nothing renders until I refresh. Any ideas?
With proper peer dependencies. See: https://twitter.com/m_kruschke/status/1148655449417367552
Hello. Nice routing library you got here. But I can't find a way to do a "default route" eg to create a 404 error route.
Can you shed some info on this?
Thanks.
Is there any way to navigate forward/back via wouter?
Right now the gzipped library size is 2KB, 70% of which is path-to-regexp
dependency. While path-to-regexp
provides a well-known way for developer to describe routes, it seems like we could shrink it's functionality to cover the 99% of use cases.
It would be cool to reimplement a limited subset of the library, so that:
For users who still want to use the path-to-regexp
functionality and get an advanced syntax we could provide an optional entry point:
import { Router } from "wouter";
import makeMatcher from "wouter/matcher";
import pathToRegexp from "path-to-regexp";
<Router matchFn={makeMatcher(pathToRegexp)}>
...
</Router>
So ideally it would be nice to define a subset of features we would like to support. Here are my ideas:
/:foo/:bar
:foo?
, :foo*
and :foo+
/:foo(\d+)/
Hi,
I could not see on the docs how to intercept the location change from a component.
Let's say I have a dirty state at the current page and want to use a custom modal component to alert the user if they want to move forward and lose data.
Thanks
Hello, wouter seems great so far!
I would like to highlight the current page's link on my navbar, is there a better way than the following?
const [, params] = useRoute("/:page");
const currentPage = params ? `/${params.page}` : "/"; //params will be null on /
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.