App
App is a DNA Component subclass that owns a Router and a History, renders the current Response and wires up navigation for its whole subtree. Every Synapse application starts by extending it.
import { App } from '@chialab/synapse';
class DemoApp extends App {
// ...
}Routes and middlewares
routes and middlewares are declared as static class properties. They are read once during initialize() and connected to the instance's router:
class DemoApp extends App {
static routes = [
{ pattern: '/', render: (req, res) => <Home /> },
{ pattern: '/users/:id', handler: (req, res) => res.setTitle(`User ${req.params.id}`), render: (req, res) => <User /> },
];
static middlewares = [new DocumentMetaMiddleware()];
}Each static array element can be a plain rule object (RouteRule / MiddlewareRule) or a Route / Middleware instance — see Routing and Middleware. The instance-level routes and middlewares properties expose the same lists reactively: reassigning them (before the router starts) disconnects the previous set and reconnects the new one.
history and router
Both are reactive properties, resolved lazily in initialize() if not provided:
history— aHistoryinstance (in-memory by default). Pass aBrowserHistoryinstance to sync with the real address bar (see History).router— aRouterinstance, created automatically and bound tohistory,originandbase.
Neither can be reassigned once the router is running — doing so throws Cannot change application router while running..
origin and base
Two string properties forwarded to the router (Router#setOrigin / Router#setBase) whenever they change:
origin— restricts navigation to a specific origin (defaults towindow.location.origin).base— the base path every route is resolved against. A value starting with#is treated as a hash-based base and resolved against the currentlocation.pathname/search(useful for static hosting, as in thedemo/navigationexample:base=${${location.pathname}#!/}).
request and response
State properties holding the current Request and Response (see Request & Response). response is what render() passes down:
render() {
if (!this.response) {
return null;
}
return <Page response={this.response} />;
}Override render() and call super.render() to wrap the current page with a shared layout, as in the Get started example.
Starting and stopping
start(path?: string): Promise<Response | void>— binds the router'spopstate/pushstate/replacestateevents and callsrouter.start(path), which replaces the current state withpath(or the current URL, forBrowserHistory, or/otherwise). Throws if called twice.stop()— detaches the listeners and callsrouter.stop().navigate(path, init?): Promise<Response | null>— delegates torouter.navigate().replace(path, init?): Promise<Response | null>— delegates torouter.replace().
autostart is a property (boolean or string) that, when truthy, calls start() automatically from connectedCallback(); a string value is used as the initial path.
Anchor and form interception
App listens for click on a and submit on form (via DNA's @listen decorator) anywhere in its subtree:
handleLink(event, node)— for a same-origin anchor whosetargetis_self(or unset), it resolves thehrefto a router path withrouter.pathFromUrl(), prevents the default navigation and callsnavigate().handleSubmit(event, node)— same resolution for a form'saction.GETforms are turned into a query string appended tonavigate(); other methods are sent asnavigate(path, { method, data })with aFormDatabuilt from the form.
Both no-op if the router hasn't started, and both can be overridden to customize or opt out of the interception for specific cases.
Lifecycle hooks
onRequest(oldValue, newValue)— called via@observe('request')wheneverthis.requestchanges.onResponse(oldValue, newValue)— called via@observe('response')wheneverthis.responsechanges.onPopState({ state, previous })— called for every routerpopstate/pushstate/replacestateevent, afterthis.requestis updated and beforethis.responseis; the default implementation computesnavigationDirection('back'or'forward') by comparingstate/previouswithhistory.compareStates().
Override any of them in a subclass (calling super is not required, they're empty by default except onPopState) to react to navigation, e.g. to send analytics or scroll to top.
TIP
Need the App or Router from a function component rendered inside it, rather than a subclass? See the useApp/useRouter hooks.