Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

doasync/trace-router

Open more actions menu

Repository files navigation

NPM Version NPM Downloads GitHub issues

Trace Router

The next generation router for your app

Installation

yarn add effector trace-router

Examples

Create a router:

import history from 'history/browser';
import { createRouter, history } from 'trace-router';

export const router = createRouter({ history });

Create routes:

// This route is used only for redirection below
export const exactRoot = router.add({ path: '/' });

// User section
export const user = router.add('/user(/.*)?'); // parent route
export const userProfile = router.add('/user');
export const userTickets = router.add('/user/tickets');
export const userTicket = router.add<{ id: number }>('/user/tickets/:id');

// Info section
export const joinUs = router.add('/join-us');
export const about = router.add('/about');
export const privacy = router.add('/privacy');

// Merge routes to create a parent route
// When you can't create common path
export const info = router.merge([joinUs, about, privacy]);

// Redirect from "/" to "/user"
exactRoot.visible.watch(visible => {
  if (visible) {
    user.redirect();
  }
});

Use routes in React (trace-router-react package):

export const Root = () => (
  <>
    {useRoute(user) && <UserPage />}
    {useRoute(info) && <InfoPage />}
    {useStore(router.noMatches) && <NotFound />}
  </>
);

export const UserPage = () => (
  <AppFrame>
    <UserTemplate>
      {useRoute(userProfile) && <UserProfile />}
      {useRoute(userTickets) && <UserTickets />}
      {useRoute(userTicket) && <UserTicket />}
    </UserTemplate>
  </AppFrame>
);

export const InfoPage = () => (
  <AppFrame>
    <InfoTemplate>
      {useRoute(joinUs) && <JoinUs />}
      {useRoute(about) && <About />}
      {useRoute(privacy) && <Privacy />}
    </InfoTemplate>
  </AppFrame>
);

You can also use Route component instead of a hook:

<Route of={map} component={MapPage} />

Use links to navigate routes directly:

<Link to={about}>About</Link>

Use can add params to the route (if it has ones):

<Link to={userTicket} params={{ id: 100 }}>
  Month
</Link>

The above link compiles to something like:

<a href="/user-tiket/100" onClick={/* prevent default & navigate */}>
  Join Us
</a>

Here is how you compile route to a string:

const href = route.compile({
  params: { id: 100 },
  query: {
    lang: 'ru',
  },
  hash: '#description',
});

Manual route navigation:

<Button onClick={() => product.navigate({ id: '100' })} />

or redirect + compile as an example:

<Button
  onClick={() =>
    product.router.redirect({
      to: product.compile({ params: { id: '100' } }),
      state: { back },
    })
  }
/>

You can use another history for a router:

import hashHistory from 'history/hash';
import { router } from '~/core/router';

router.use(hashHistory);

You can bind one router to another:

export const product = router
  .add<{ tab: string }>('/product:tab(.*)?')
  .bind('tab', { router: tabRouter });

.bind method binds child router path to a parent router parameter

You can have an url /product/info where: /product - the path of the main router (without a parameter) /info - tabRouter path

Types

Router
export type Router<Q extends Query = Query, S extends State = State> = {
  history: History<S>;
  historyUpdated: Event<Update<S>>;
  historyUpdate: Store<Update<S>>;
  navigate: Event<ToLocation<S>>;
  redirect: Event<ToLocation<S>>;
  shift: Event<Delta>;
  back: Event<void>;
  forward: Event<void>;
  location: Store<Location<S>>;
  action: Store<Action>;
  pathname: Store<Pathname>;
  search: Store<Search>;
  hash: Store<Hash>;
  state: Store<S>;
  key: Store<Key>;
  href: Store<Href>;
  query: Store<Q>;
  hasMatches: Store<boolean>;
  noMatches: Store<boolean>;
  add: <P extends Params = Params>(
    pathConfig: Pattern | RouteConfig
  ) => Route<P, Router<Q, S>>;
  merge: <T extends Route[]>(routes: T) => MergedRoute;
  none: <T extends Route[]>(routes: T) => MergedRoute;
  use: (
    givenHistory: BrowserHistory<S> | HashHistory<S> | MemoryHistory<S>
  ) => void;
};
Route
export type Route<P extends Params = Params, R = Router> = {
  visible: Store<boolean>;
  params: Store<null | P>;
  config: RouteConfig;
  compile: (compileConfig?: CompileConfig<P>) => string;
  router: R extends Router<infer Q, infer S> ? Router<Q, S> : never;
  navigate: Event<P | void>;
  redirect: Event<P | void>;
  bindings: Partial<{ [K in keyof P]: BindConfig }>;
  bind: (
    param: keyof P,
    bindConfig: {
      router: Router;
      parse?: (rawParam?: string) => string | undefined;
      format?: (path?: string) => string | undefined;
    }
  ) => Route<P, R>;
};
Other typings
export type ToLocation<S extends State = State> =
  | string
  | { to?: To; state?: S };
export type Delta = number;
export type Href = string;
export type Pattern = string;
export interface Query extends ObjectString {}
export interface Params extends ObjectUnknown {}

export type RouterConfig<S extends State = State> = {
  history?: BrowserHistory<S> | HashHistory<S> | MemoryHistory<S>;
  root?: InitialEntry;
};

export type RouteConfig = {
  path: Pattern;
  matchOptions?: ParseOptions & TokensToRegexpOptions & RegexpToFunctionOptions;
};

export type CompileConfig<P extends Params = Params> = {
  params?: P;
  query?: string[][] | Record<string, string> | string | URLSearchParams;
  hash?: string;
  options?: ParseOptions & TokensToFunctionOptions;
};

export type BindConfig = {
  router: Router;
  parse?: (rawParam?: string) => string | undefined;
  format?: (path?: string) => string | undefined;
};

export type MergedRoute = {
  visible: Store<boolean>;
  routes: Route[];
  configs: RouteConfig[];
};

Repo

Give trace-router a star!

GitHub ★: https://github.com/doasync/trace-router

About

The next generation router for your app

Resources

License

Stars

Watchers

Forks

Packages

No packages published
Morty Proxy This is a proxified and sanitized view of the page, visit original site.