npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

preact-router-react-stub

v0.0.11

Published

Connect your components up to that address bar.

Downloads

7

Readme

preact-router

NPM Build status

[!WARNING] preact-router unfortunately no longer sees active development! It's completely stable and so you can rely upon it for all existing apps, but for newer ones, we'd recommend using preact-iso for your routing needs instead. It offers a very similar API while integrating a bit better Suspense and lazy loading, with potentially more useful hooks. Thanks to all the contributors and users over the years!

Connect your Preact components up to that address bar.

preact-router provides a <Router /> component that conditionally renders its children when the URL matches their path. It also automatically wires up <a /> elements to the router.

💁 Note: This is not a preact-compatible version of React Router. preact-router is a simple URL wiring and does no orchestration for you.

If you're looking for more complex solutions like nested routes and view composition, react-router works great with preact as long as you alias in preact/compat.

See a Real-world Example :arrow_right:


Usage Example

import Router from 'preact-router';
import { h, render } from 'preact';
/** @jsx h */

const Main = () => (
  <Router>
    <Home path="/" />
    <About path="/about" />
    // Advanced is an optional query
    <Search path="/search/:query/:advanced?" />
  </Router>
);

render(<Main />, document.body);

If there is an error rendering the destination route, a 404 will be displayed.

Caveats

Because the path and default props are used by the router, it's best to avoid using those props for your component(s) as they will conflict.

Handling URLS

:information_desk_person: Pages are just regular components that get mounted when you navigate to a certain URL. Any URL parameters get passed to the component as props.

Defining what component(s) to load for a given URL is easy and declarative. Querystring and :parameter values are passed to the matched component as props. Parameters can be made optional by adding a ?, or turned into a wildcard match by adding * (zero or more characters) or + (one or more characters):

<Router>
  <A path="/" />
  <B path="/b" id="42" />
  <C path="/c/:id" />
  <C path="/d/:optional?/:params?" />
  <D path="/e/:remaining_path*" />
  <E path="/f/:remaining_path+" />
  <F default />
</Router>

Lazy Loading

Lazy loading (code splitting) with preact-router can be implemented easily using the AsyncRoute module:

import AsyncRoute from 'preact-async-route';
<Router>
  <Home path="/" />
  <AsyncRoute
    path="/friends"
    getComponent={() => import('./friends').then(module => module.default)}
  />
  <AsyncRoute
    path="/friends/:id"
    getComponent={() => import('./friend').then(module => module.default)}
    loading={() => <div>loading...</div>}
  />
</Router>;

Active Matching & Links

preact-router includes an add-on module called match that lets you wire your components up to Router changes.

Here's a demo of <Match>, which invokes the function you pass it (as its only child) in response to any routing:

import Router from 'preact-router';
import Match from 'preact-router/match';

render(
  <div>
    <Match path="/">{({ matches, path, url }) => <pre>{url}</pre>}</Match>
    <Router>
      <div default>demo fallback route</div>
    </Router>
  </div>
);

// another example: render only if at a given URL:

render(
  <div>
    <Match path="/">{({ matches }) => matches && <h1>You are Home!</h1>}</Match>
    <Router />
  </div>
);

<Link> is just a normal link, but it automatically adds and removes an "active" classname to itself based on whether it matches the current URL.

import { Router } from 'preact-router';
import { Link } from 'preact-router/match';

render(
  <div>
    <nav>
      <Link activeClassName="active" href="/">
        Home
      </Link>
      <Link activeClassName="active" href="/foo">
        Foo
      </Link>
      <Link activeClassName="active" href="/bar">
        Bar
      </Link>
    </nav>
    <Router>
      <div default>this is a demo route that always matches</div>
    </Router>
  </div>
);

Default Link Behavior

Sometimes it's necessary to bypass preact-router's link handling and let the browser perform routing on its own.

This can be accomplished by adding a data-native boolean attribute to any link:

<a href="/foo" data-native>Foo</a>

Detecting Route Changes

The Router notifies you when a change event occurs for a route with the onChange callback:

import { render, Component } from 'preact';
import { Router, route } from 'preact-router';

class App extends Component {
  // some method that returns a promise
  isAuthenticated() {}

  handleRoute = async e => {
    switch (e.url) {
      case '/profile':
        const isAuthed = await this.isAuthenticated();
        if (!isAuthed) route('/', true);
        break;
    }
  };

  render() {
    return (
      <Router onChange={this.handleRoute}>
        <Home path="/" />
        <Profile path="/profile" />
      </Router>
    );
  }
}

Redirects

Can easily be implemented with a custom Redirect component;

import { Component } from 'preact';
import { route } from 'preact-router';

export default class Redirect extends Component {
  componentWillMount() {
    route(this.props.to, true);
  }

  render() {
    return null;
  }
}

Now to create a redirect within your application, you can add this Redirect component to your router;

<Router>
  <Bar path="/bar" />
  <Redirect path="/foo" to="/bar" />
</Router>

Custom History

It's possible to use alternative history bindings, like /#!/hash-history:

import { h } from 'preact';
import Router from 'preact-router';
import { createHashHistory } from 'history';

const Main = () => (
  <Router history={createHashHistory()}>
    <Home path="/" />
    <About path="/about" />
    <Search path="/search/:query" />
  </Router>
);

render(<Main />, document.body);

Programmatically Triggering Route

It's possible to programmatically trigger a route to a page (like window.location = '/page-2')

import { route } from 'preact-router';

route('/page-2'); // appends a history entry

route('/page-3', true); // replaces the current history entry

Nested Routers

The <Router> is a self-contained component that renders based on the page URL. When nested a Router inside of another Router, the inner Router does not share or observe the outer's URL or matches. Instead, inner routes must include the full path to be matched against the page's URL:

import { h, render } from 'preact';
import Router from 'preact-router';

function Profile(props) {
  // `props.rest` is the rest of the URL after "/profile/"
  return (
    <div>
      <h1>Profile</h1>
      <Router>
        <MyProfile path="/profile/me" />
        <UserProfile path="/profile/:user" />
      </Router>
    </div>
  );
}
const MyProfile = () => <h2>My Profile</h2>;
const UserProfile = props => <h2>{props.user}</h2>;

function App() {
  return (
    <div>
      <Router>
        <Home path="/" />
        <Profile path="/profile/:rest*" />
      </Router>
      <nav>
        <a href="/">Home</a>
        <a href="/profile/me">My Profile</a>
        <a href="/profile/alice">Alice's Profile</a>
      </nav>
    </div>
  );
}

render(<App />, document.body);

Route Component

Alternatively to adding the router props (path, default) directly to your component, you may want to use the Route component we provide instead. This tends to appease TypeScript, while still passing down the routing props into your component for use.

import { Router, Route } from 'preact-router';

function App() {
  let users = getUsers();

  return (
    <Router>
      <Route path="/" component={Home} />
      {/* Route will accept any props of `component` type */}
      <Route path="/users" component={Users} users={users}   />
    </Router>
  );
}

License

MIT