This package contains routing functionalities for Preact and, now from 1.0.0 React
applications as well. Instead of using HTML5 history API it uses the oldie /#/what-ever
hash routing (this will change in the future).
This project was created by exploring contextual ways to define routes rather than placing all the routes in a single file.
Available imports:
// if you're using React
import { renderOnRoute, navigate, RouterOutlet, PathLookup, routePool, Link } from "preact-routlet/react"
// if you're using Preact
import { renderOnRoute, navigate, RouterOutlet, PathLookup, routePool, Link } from "preact-routlet/preact"
Either from "preact-routlet/preact"
or from "preact-routlet/react"
Place your RouterOutlet
element somewhere in your JSX:
<div>
<RouterOutlet />
</div>
Plug the renderOnRoute
decorator on some component
@renderOnRoute("/login")
export default class Login extends Component<any, any> {
...
}
Remember to import your class to evaluate your component
import './components/login';
You dont need to instantiate or declare it. Just import it on your app index.
A good practice is to group your components by domain:
For example imagine the following index
file:
import { h, render } from "preact";
import Main from "./common/main";
/* domain */
import "./domain/access";
import "./domain/dashboard";
render(<Main />, document.querySelector("#root"));
Then you have some kind of folder structure like this:
src/domain/
├── access
│ ├── index.tsx
│ ├── models
│ ├── pages
│ └── share
└── dashboard
└── index.tsx
on each index
file you're importing your components:
$ cat src/domain/access/index.tsx
import "./pages/login-page";
import "./pages/register-page";
import "./pages/forgot-password-page";
So basically you're registering all the components that listen to route changes in your app.
404 routes: If none of the components are listening for some particular route
<div>
<RouterOutlet>
<ThisComponentWillBeRenderedOtherwise />
</RouterOutlet>
</div>
Conditional rendering on route (declarative)
<PathLookup shouldRender={path => predicate}>
<ComponentThatWillBeRenderedIfPredicateReturnsTrue />
</PathLookup>
Navigation (code)
...
navigate("/somewhere");
Navigation (declarative)
<Link href="https://github.com/k1r0s/preact-routlet/blob/master/somewhere">Go to somewhere</Link>
Redirect if some condition was not fulfilled
<RouterOutlet redirect="/login" shouldRedirect={path => requireLogin(path) && !AuthService.isLogged()} />
Lazy loading, Module splitting
By default routes are only loaded if you evaluate classes that contain the @renderOnRoute
decorator, so simply by importing it. But you need the plugin syntax-dynamic-import
to dynamically use the import() function with Babel.
...
} else if (User.isAdmin(userSnapshot)) {
import('../admin'); //load admin module
}
// admin/index.js
...
import { navigate } from 'preact-routlet/react'; // import navigate function
import './dashboard'; //load component with @renderOnRoute
import './user-list'; //load component with @renderOnRoute
navigate('/admin-board'); //navigate to this module once routes are loaded
By using @renderOnRoute
you're adding the evaluated component to the route pool