Skip to content

@effector/routerA route is a unit of logic

Model navigation as state and events — then render it anywhere.

Type-safe·Framework-agnostic·Observable
page.model.ts
import { beforeNavigate, chainRoute } from '@effector/router'
import { sample } from 'effector'

// Hold navigation until the guard resolves
const guard = beforeNavigate({
  controls,
  to: dashboardRoute,
  filter: $unauthorized,
})

sample({
  clock: guard.started,
  target: redirect({ to: loginRoute }),
})

// Open the route only after data is ready
const readyDashboard = chainRoute({
  route: dashboardRoute,
  beforeOpen: loadDashboardFx,
})

NAVIGATION IS STATE

Watch the model move

Every route is an Effector unit. Change the URL or open a route — the graph and every store update in lockstep. This is state you can observe, combine and test, not a side effect of rendering.

router.$path

routes

stores

router.$path/
feedRoute.$isOpenedfalse
postRoute.$isOpenedfalse
profileRoute.$isOpenedfalse
settingsModal.$isOpenedfalse
none.$params{}

events

open a route to fire opened / closed

THE CORE IDEA

Routes without URLs

In most routers a route is a URL. Here a route is a unit of state and events that may or may not have a path. Modals, wizard steps and native screens become first-class routes — and the URL is just one adapter you plug in later.

  • No inline URLs. Features open a route object, not a string. Restructure your URLs in one place.
  • Pathless by default. createRoute() works with no path at all.
  • Assign paths centrally when you register routes in the router.
// A modal is a route with no URL
const settingsModal = createRoute()

// A screen is a route with a typed path
const userRoute = createRoute({
  path: '/user/:id',
}) // Route<{ id: string }>

// URLs live in one place — the router
const router = createRouter({
  routes: [
    userRoute,
    { path: '/settings', route: settingsModal },
  ],
})

HOW IT DIFFERS

A different model, on purpose

Most routers treat a route as a URL, and navigation as a side effect of rendering. Here a route is an Effector unit — so navigation is state you can observe, combine and test without a DOM.

Most routers

  • A route is a URL string
  • Navigation lives inside components
  • Params typed by hand, checked at runtime
  • Modals and wizards aren't routes
  • SSR needs a dedicated integration

@effector/router

  • A route is a unit of state and events
  • Navigation is driven from your model with sample
  • Params inferred from the path, checked by the compiler
  • Pathless routes model modals, steps and native screens
  • Isomorphism comes from Effector — fork a scope, serialize

Not a replacement for react-router or TanStack Router — a different answer for apps already modelling logic in Effector.

Released under the MIT License.