• Stars
    star
    972
  • Rank 45,257 (Top 1.0 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 8 years ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

🌎 URL router for Preact.

preact-router

NPM Build status

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 ➡️


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.

Handling URLS

💁 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);

License

MIT

More Repositories

1

preact

⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.
JavaScript
36,018
star
2

wmr

👩‍🚀 The tiny all-in-one development tool for modern web apps.
JavaScript
4,924
star
3

preact-cli

😺 Your next Preact PWA starts in 30 seconds.
JavaScript
4,678
star
4

signals

Manage state with style in every framework
TypeScript
2,105
star
5

preact-compat

ATTENTION: The React compatibility layer for Preact has moved to the main preact repo.
JavaScript
951
star
6

awesome-preact

A curated list of amazingly awesome things regarding Preact ecosystem 🌟
848
star
7

preact-render-to-string

📄 Universal rendering for Preact: render JSX and Preact components to HTML.
JavaScript
574
star
8

compressed-size-action

GitHub Action that adds compressed size changes to your PRs.
JavaScript
541
star
9

next-plugin-preact

Next.js plugin for preact X
JavaScript
391
star
10

prefresh

Hot Module Reloading for Preact
JavaScript
351
star
11

preact-www

📖 Preact documentation website.
JavaScript
348
star
12

preact-custom-element

Wrap your component up as a custom element
JavaScript
343
star
13

preact-devtools

Browser extension for inspection Preact applications
TypeScript
295
star
14

preset-vite

Preset for using Preact with the vite bundler
TypeScript
233
star
15

eslint-config-preact

Unopinionated baseline ESLint config for Preact and Preact CLI codebases.
JavaScript
85
star
16

enzyme-adapter-preact-pure

Preact adapter for the Enzyme UI testing library
TypeScript
67
star
17

preact-ssr-prepass

Drop-in replacement for react-ssr-prepass
JavaScript
47
star
18

preact-integrations

A collection of sample apps demonstrating Preact's compatibility with various 3rd party libraries
JavaScript
35
star
19

rfcs

RFCs for changes and ideas in relation to Preact
30
star
20

create-preact

Create a Vite-powered Preact app in seconds
JavaScript
24
star
21

babel-plugin-transform-replace-expressions

A Babel plugin for replacing expressions with other expressions
JavaScript
23
star
22

jest-preset-preact

Jest preset for testing Preact apps
JavaScript
19
star
23

babel-plugin-transform-rename-properties

A Babel plugin for renaming JavaScript properties
JavaScript
19
star
24

preact-netlify

Preact's netlify CMS template
JavaScript
16
star
25

legacy-compat

React 15 compatibility layer for Preact
JavaScript
16
star
26

playwright-ct

Preact adapter for Playwright Component testing
TypeScript
15
star
27

preact-iso

Isomorphic utilities for Preact
JavaScript
12
star
28

compat-alias-package

JavaScript
10
star
29

babel-plugin-transform-hook-names

Add custom hook names for devtools
TypeScript
7
star
30

migrate-preact-x

JavaScript
6
star
31

preact-cli-experiment

TypeScript
4
star
32

codesandbox-template

JavaScript
4
star
33

.github

Default community files for the PreactJS organization
3
star